summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSE Android <seandroid@taiga.selinuxproject.org>2012-01-24 05:26:38 -0800
committerSE Android <seandroid@taiga.selinuxproject.org>2012-01-24 05:26:38 -0800
commit255e72915d4cbddceb435e13d81601755714e9f3 (patch)
treed9e146f714ac6197865554529bcd1e3d10cbaec2
downloadlibsepol-255e72915d4cbddceb435e13d81601755714e9f3.tar.gz
Import libsepol 2.1.0 (Release 2011-07-27).
-rw-r--r--.gitignore1
-rw-r--r--COPYING504
-rw-r--r--ChangeLog750
-rw-r--r--Makefile26
-rw-r--r--VERSION1
-rw-r--r--include/Makefile12
-rw-r--r--include/sepol/boolean_record.h51
-rw-r--r--include/sepol/booleans.h59
-rw-r--r--include/sepol/context.h25
-rw-r--r--include/sepol/context_record.h53
-rw-r--r--include/sepol/debug.h34
-rw-r--r--include/sepol/errcodes.h25
-rw-r--r--include/sepol/handle.h27
-rw-r--r--include/sepol/iface_record.h59
-rw-r--r--include/sepol/interfaces.h43
-rw-r--r--include/sepol/module.h82
-rw-r--r--include/sepol/node_record.h92
-rw-r--r--include/sepol/nodes.h40
-rw-r--r--include/sepol/policydb.h138
-rw-r--r--include/sepol/policydb/avrule_block.h37
-rw-r--r--include/sepol/policydb/avtab.h127
-rw-r--r--include/sepol/policydb/conditional.h134
-rw-r--r--include/sepol/policydb/constraint.h77
-rw-r--r--include/sepol/policydb/context.h97
-rw-r--r--include/sepol/policydb/ebitmap.h88
-rw-r--r--include/sepol/policydb/expand.h79
-rw-r--r--include/sepol/policydb/flask.h94
-rw-r--r--include/sepol/policydb/flask_types.h62
-rw-r--r--include/sepol/policydb/hashtab.h137
-rw-r--r--include/sepol/policydb/hierarchy.h32
-rw-r--r--include/sepol/policydb/link.h20
-rw-r--r--include/sepol/policydb/mls_types.h153
-rw-r--r--include/sepol/policydb/module.h48
-rw-r--r--include/sepol/policydb/polcaps.h18
-rw-r--r--include/sepol/policydb/policydb.h724
-rw-r--r--include/sepol/policydb/services.h184
-rw-r--r--include/sepol/policydb/sidtab.h72
-rw-r--r--include/sepol/policydb/symtab.h38
-rw-r--r--include/sepol/policydb/util.h31
-rw-r--r--include/sepol/port_record.h66
-rw-r--r--include/sepol/ports.h40
-rw-r--r--include/sepol/roles.h10
-rw-r--r--include/sepol/sepol.h28
-rw-r--r--include/sepol/user_record.h76
-rw-r--r--include/sepol/users.h57
-rw-r--r--man/Makefile10
-rw-r--r--man/man3/sepol_check_context.325
-rw-r--r--man/man3/sepol_genbools.330
-rw-r--r--man/man3/sepol_genusers.354
-rw-r--r--man/man8/chkcon.841
-rw-r--r--man/man8/genpolbools.816
-rw-r--r--man/man8/genpolusers.842
-rw-r--r--src/Makefile56
-rw-r--r--src/assertion.c151
-rw-r--r--src/av_permissions.h3
-rw-r--r--src/avrule_block.c202
-rw-r--r--src/avtab.c531
-rw-r--r--src/boolean_internal.h16
-rw-r--r--src/boolean_record.c180
-rw-r--r--src/booleans.c216
-rw-r--r--src/conditional.c905
-rw-r--r--src/constraint.c47
-rw-r--r--src/context.c338
-rw-r--r--src/context.h37
-rw-r--r--src/context_internal.h19
-rw-r--r--src/context_record.c324
-rw-r--r--src/debug.c89
-rw-r--r--src/debug.h74
-rw-r--r--src/dso.h23
-rw-r--r--src/ebitmap.c368
-rw-r--r--src/expand.c3179
-rw-r--r--src/genbools.c252
-rw-r--r--src/genusers.c318
-rw-r--r--src/handle.c45
-rw-r--r--src/handle.h23
-rw-r--r--src/hashtab.c313
-rw-r--r--src/hierarchy.c501
-rw-r--r--src/iface_internal.h18
-rw-r--r--src/iface_record.c233
-rw-r--r--src/interfaces.c273
-rw-r--r--src/libsepol.map19
-rw-r--r--src/libsepol.pc.in11
-rw-r--r--src/link.c2598
-rw-r--r--src/mls.c798
-rw-r--r--src/mls.h67
-rw-r--r--src/module.c985
-rw-r--r--src/module_internal.h5
-rw-r--r--src/node_internal.h26
-rw-r--r--src/node_record.c668
-rw-r--r--src/nodes.c400
-rw-r--r--src/polcaps.c33
-rw-r--r--src/policydb.c3843
-rw-r--r--src/policydb_convert.c100
-rw-r--r--src/policydb_internal.h10
-rw-r--r--src/policydb_public.c193
-rw-r--r--src/port_internal.h20
-rw-r--r--src/port_record.c288
-rw-r--r--src/ports.c312
-rw-r--r--src/private.h49
-rw-r--r--src/roles.c55
-rw-r--r--src/services.c1469
-rw-r--r--src/sidtab.c328
-rw-r--r--src/symtab.c49
-rw-r--r--src/user_internal.h20
-rw-r--r--src/user_record.c379
-rw-r--r--src/users.c383
-rw-r--r--src/util.c116
-rw-r--r--src/write.c2009
-rw-r--r--tests/Makefile54
-rw-r--r--tests/debug.c69
-rw-r--r--tests/debug.h27
-rw-r--r--tests/helpers.c81
-rw-r--r--tests/helpers.h59
-rw-r--r--tests/libsepol-tests.c118
-rw-r--r--tests/policies/support/misc_macros.spt23
-rw-r--r--tests/policies/test-cond/refpolicy-base.conf1939
-rw-r--r--tests/policies/test-deps/base-metreq.conf519
-rw-r--r--tests/policies/test-deps/base-notmetreq.conf506
-rw-r--r--tests/policies/test-deps/modreq-attr-global.conf10
-rw-r--r--tests/policies/test-deps/modreq-attr-opt.conf16
-rw-r--r--tests/policies/test-deps/modreq-bool-global.conf15
-rw-r--r--tests/policies/test-deps/modreq-bool-opt.conf22
-rw-r--r--tests/policies/test-deps/modreq-obj-global.conf13
-rw-r--r--tests/policies/test-deps/modreq-obj-opt.conf20
-rw-r--r--tests/policies/test-deps/modreq-perm-global.conf10
-rw-r--r--tests/policies/test-deps/modreq-perm-opt.conf18
-rw-r--r--tests/policies/test-deps/modreq-role-global.conf13
-rw-r--r--tests/policies/test-deps/modreq-role-opt.conf17
-rw-r--r--tests/policies/test-deps/modreq-type-global.conf12
-rw-r--r--tests/policies/test-deps/modreq-type-opt.conf16
-rw-r--r--tests/policies/test-deps/module.conf20
-rw-r--r--tests/policies/test-deps/small-base.conf511
-rw-r--r--tests/policies/test-expander/alias-base.conf498
-rw-r--r--tests/policies/test-expander/alias-module.conf8
-rw-r--r--tests/policies/test-expander/base-base-only.conf43
-rw-r--r--tests/policies/test-expander/module.conf228
-rw-r--r--tests/policies/test-expander/role-base.conf479
-rw-r--r--tests/policies/test-expander/role-module.conf9
-rw-r--r--tests/policies/test-expander/small-base.conf718
-rw-r--r--tests/policies/test-expander/user-base.conf482
-rw-r--r--tests/policies/test-expander/user-module.conf9
-rw-r--r--tests/policies/test-hooks/cmp_policy.conf471
-rw-r--r--tests/policies/test-hooks/module_add_role_allow_trans.conf15
-rw-r--r--tests/policies/test-hooks/module_add_symbols.conf12
-rw-r--r--tests/policies/test-hooks/small-base.conf471
-rw-r--r--tests/policies/test-linker/module1.conf138
-rw-r--r--tests/policies/test-linker/module2.conf62
-rw-r--r--tests/policies/test-linker/small-base.conf593
-rw-r--r--tests/test-common.c262
-rw-r--r--tests/test-common.h78
-rw-r--r--tests/test-cond.c95
-rw-r--r--tests/test-cond.h30
-rw-r--r--tests/test-deps.c302
-rw-r--r--tests/test-deps.h30
-rw-r--r--tests/test-downgrade.c273
-rw-r--r--tests/test-downgrade.h119
-rw-r--r--tests/test-expander-attr-map.c105
-rw-r--r--tests/test-expander-attr-map.h26
-rw-r--r--tests/test-expander-roles.c37
-rw-r--r--tests/test-expander-roles.h27
-rw-r--r--tests/test-expander-users.c75
-rw-r--r--tests/test-expander-users.h27
-rw-r--r--tests/test-expander.c218
-rw-r--r--tests/test-expander.h30
-rw-r--r--tests/test-linker-cond-map.c159
-rw-r--r--tests/test-linker-cond-map.h27
-rw-r--r--tests/test-linker-roles.c206
-rw-r--r--tests/test-linker-roles.h29
-rw-r--r--tests/test-linker-types.c317
-rw-r--r--tests/test-linker-types.h27
-rw-r--r--tests/test-linker.c154
-rw-r--r--tests/test-linker.h30
-rw-r--r--utils/Makefile24
-rw-r--r--utils/chkcon.c42
174 files changed, 39829 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a74c98b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+utils/chkcon
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..8d9c9c0
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,750 @@
+2.1.0 2011-07-27
+ * Release, minor version bump
+
+2.0.46 2011-07-25
+ * Add role attribute support by Harry Ciao
+
+2.0.45 2011-05-02
+ * Warn if filename_trans rules are dropped by Steve Lawrence.
+
+2.0.44 2011-04-13
+ * Fixes for new role_transition class field by Eric Paris.
+ * Add libsepol support for filename_trans rules by Eric Paris.
+
+2.0.43 2011-04-11
+ * Add new class field in role_transition by Harry Ciao.
+
+2.0.42 2010-12-16
+ * Fix compliation under GCC 4.6 by Justin Mattock
+
+2.0.41 2009-11-18
+ * Fixed typo in error message from Manoj Srivastava.
+
+2.0.40 2009-10-29
+ * Add pkgconfig file from Eamon Walsh.
+
+2.0.39 2009-10-14
+ * Add support for building Xen policies from Paul Nuzzi.
+
+2.0.38 2009-09-01
+ * Check last offset in the module package against the file size.
+ Reported by Manoj Srivastava for bug filed by Max Kellermann.
+
+2.0.37 2009-07-07
+ * Add method to check disable dontaudit flag from Christopher Pardy.
+
+2.0.36 2009-03-25
+ * Fix boolean state smashing from Joshua Brindle.
+
+2.0.35 2009-02-19
+ * Fix alias field in module format, caused by boundary format change
+ from Caleb Case.
+
+2.0.34 2008-10-09
+ * Add bounds support from KaiGai Kohei.
+ * Fix invalid aliases bug from Joshua Brindle.
+
+2.0.33 2008-09-29
+ * Revert patch that removed expand_rule.
+
+2.0.32 2008-07-07
+ * Allow require then declare in the source policy from Joshua Brindle.
+
+2.0.31 2008-06-13
+ * Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley.
+
+2.0.30 2008-06-06
+ * Fix endianness bug in the handling of network node addresses from Stephen Smalley.
+ Only affects big endian platforms.
+ Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc.
+
+2.0.29 2008-05-27
+ * Merge user and role mapping support from Joshua Brindle.
+
+2.0.28 2008-05-05
+ * Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley.
+
+2.0.27 2008-04-18
+ * Belatedly merge test for policy downgrade from Todd Miller.
+
+2.0.26 2008-03-24
+ * Add permissive domain support from Eric Paris.
+
+2.0.25 2008-03-04
+ * Drop unused ->buffer field from struct policy_file.
+
+2.0.24 2008-03-04
+ * Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller.
+
+2.0.23 2008-02-28
+ * Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley.
+
+2.0.22 2008-02-28
+ * Add support for open_perms policy capability from Eric Paris.
+
+2.0.21 2008-02-20
+ * Fix invalid memory allocation in policydb_index_others() from Jason Tang.
+
+2.0.20 2008-02-04
+ * Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley.
+
+2.0.19 2008-02-02
+ * Add support for consuming avrule_blocks during expansion to reduce
+ peak memory usage from Joshua Brindle.
+
+2.0.18 2008-01-02
+ * Added support for policy capabilities from Todd Miller.
+
+2.0.17 2007-12-21
+ * Prevent generation of policy.18 with MLS enabled from Todd Miller.
+
+2.0.16 2007-12-07
+ * print module magic number in hex on mismatch, from Todd Miller.
+
+2.0.15 2007-11-29
+ * clarify and reduce neverallow error reporting from Stephen Smalley.
+
+2.0.14 2007-11-05
+ * Reject self aliasing at link time from Stephen Smalley.
+
+2.0.13 2007-11-05
+ * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley.
+
+2.0.12 2007-10-11
+ * Fixed bug in require checking from Stephen Smalley.
+ * Added user hierarchy checking from Todd Miller.
+
+2.0.11 2007-09-24
+ * Pass CFLAGS to CC even on link command, per Dennis Gilmore.
+
+2.0.10 2007-09-18
+ * Merged support for the handle_unknown policydb flag from Eric Paris.
+
+2.0.9 2007-08-29
+ * Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper.
+
+2.0.8 2007-08-28
+ * Fixed module_package_read_offsets bug introduced by the prior patch.
+
+2.0.7 2007-08-23
+ * Eliminate unaligned accesses from policy reading code from Stephen Smalley.
+
+2.0.6 2007-08-16
+ * Allow dontaudits to be turned off during policy expansion from
+ Joshua Brindle.
+
+2.0.5 2007-08-01
+ * Fix sepol_context_clone to handle a NULL context correctly.
+ This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL)
+ to set the file context entry to "<<none>>".
+
+2.0.4 2007-06-20
+ * Merged error handling patch from Eamon Walsh.
+
+2.0.3 2007-04-13
+ * Merged add boolmap argument to expand_module_avrules() from Chris PeBenito.
+
+2.0.2 2007-03-30
+ * Merged fix from Karl to remap booleans at expand time to
+ avoid holes in the symbol table.
+
+2.0.1 2007-02-06
+ * Merged libsepol segfault fix from Stephen Smalley for when
+ sensitivities are required but not present in the base.
+
+2.0.0 2007-02-01
+ * Merged patch to add errcodes.h to libsepol by Karl MacMillan.
+
+1.16.0 2007-01-18
+ * Updated version for stable branch.
+
+1.15.3 2006-11-27
+ * Merged patch to compile wit -fPIC instead of -fpic from
+ Manoj Srivastava to prevent hitting the global offest table
+ limit. Patch changed to include libselinux and libsemanage in
+ addition to libselinux.
+1.15.2 2006-10-31
+ * Merged fix from Karl MacMillan for a segfault when linking
+ non-MLS modules with users in them.
+
+1.15.1 2006-10-24
+ * Merged fix for version comparison that was preventing range
+ transition rules from being written for a version 5 base policy
+ from Darrel Goeddel.
+
+1.14 2006-10-17
+ * Updated version for release.
+
+1.12.28 2006-09-28
+ * Build libsepol's static object files with -fpic
+
+1.12.27 2006-09-28
+ * Merged mls user and range_transition support in modules
+ from Darrel Goeddel
+
+1.12.26 2006-09-05
+ * Merged range transition enhancements and user format changes
+ Darrel Goeddel
+
+1.12.25 2006-08-24
+ * Merged conditionally expand neverallows patch from Jeremy Mowery.
+ * Merged refactor expander patch from Jeremy Mowery.
+
+1.12.24 2006-08-03
+ * Merged libsepol unit tests from Joshua Brindle.
+
+1.12.23 2006-08-03
+ * Merged symtab datum patch from Karl MacMillan.
+
+1.12.22 2006-08-03
+ * Merged netfilter contexts support from Chris PeBenito.
+
+1.12.21 2006-07-28
+ * Merged helpful hierarchy check errors patch from Joshua Brindle.
+
+1.12.20 2006-07-25
+ * Merged semodule_deps patch from Karl MacMillan.
+ This adds source module names to the avrule decls.
+
+1.12.19 2006-06-29
+ * Lindent.
+
+1.12.18 2006-06-26
+ * Merged optionals in base take 2 patch set from Joshua Brindle.
+
+1.12.17 2006-05-30
+ * Revert 1.12.16.
+
+1.12.16 2006-05-30
+ * Merged cleaner fix for bool_ids overflow from Karl MacMillan,
+ replacing the prior patch.
+
+1.12.15 2006-05-30
+ * Merged fixes for several memory leaks in the error paths during
+ policy read from Serge Hallyn.
+
+1.12.14 2006-05-25
+ * Fixed bool_ids overflow bug in cond_node_find and cond_copy_list,
+ based on bug report and suggested fix by Cedric Roux.
+
+1.12.13 2006-05-24
+ * Merged sens_copy_callback, check_role_hierarchy_callback,
+ and node_from_record fixes from Serge Hallyn.
+
+1.12.12 2006-05-22
+ * Added sepol_policydb_compat_net() interface for testing whether
+ a policy requires the compatibility support for network checks
+ to be enabled in the kernel.
+
+1.12.11 2006-05-17
+ * Merged patch to initialize sym_val_to_name arrays from Kevin Carr.
+ Reworked to use calloc in the first place, and converted some other
+ malloc/memset pairs to calloc calls.
+
+1.12.10 2006-05-08
+ * Merged patch to revert role/user decl upgrade from Karl MacMillan.
+
+1.12.9 2006-05-08
+ * Dropped tests from all Makefile target.
+
+1.12.8 2006-05-05
+ * Merged fix warnings patch from Karl MacMillan.
+
+1.12.7 2006-05-05
+ * Merged libsepol test framework patch from Karl MacMillan.
+
+1.12.6 2006-04-28
+ * Fixed cond_normalize to traverse the entire cond list at link time.
+
+1.12.5 2006-04-03
+ * Merged fix for leak of optional package sections from Ivan Gyurdiev.
+
+1.12.4 2006-03-29
+ * Generalize test for bitmap overflow in ebitmap_set_bit.
+
+1.12.3 2006-03-27
+ * Fixed attr_convert_callback and expand_convert_type_set
+ typemap bug.
+
+1.12.2 2006-03-24
+ * Fixed avrule_block_write num_decls endian bug.
+
+1.12.1 2006-03-20
+ * Fixed sepol_module_package_write buffer overflow bug.
+
+1.12 2006-03-14
+ * Updated version for release.
+
+1.11.20 2006-03-08
+ * Merged cond_evaluate_expr fix from Serge Hallyn (IBM).
+ * Fixed bug in copy_avrule_list reported by Ivan Gyurdiev.
+
+1.11.19 2006-02-21
+ * Merged sepol_policydb_mls_enabled interface and error handling
+ changes from Ivan Gyurdiev.
+
+1.11.18 2006-02-16
+ * Merged node_expand_addr bugfix and node_compare* change from
+ Ivan Gyurdiev.
+
+1.11.17 2006-02-15
+ * Merged nodes, ports: always prepend patch from Ivan Gyurdiev.
+ * Merged bug fix patch from Ivan Gyurdiev.
+
+1.11.16 2006-02-14
+ * Added a defined flag to level_datum_t for use by checkpolicy.
+
+1.11.15 2006-02-14
+ * Merged nodecon support patch from Ivan Gyurdiev.
+ * Merged cleanups patch from Ivan Gyurdiev.
+
+1.11.14 2006-02-13
+ * Merged optionals in base patch from Joshua Brindle.
+
+1.11.13 2006-02-07
+ * Merged seuser/user_extra support patch from Joshua Brindle.
+ * Merged fix patch from Ivan Gyurdiev.
+
+1.11.12 2006-02-02
+ * Merged clone record on set_con patch from Ivan Gyurdiev.
+
+1.11.11 2006-02-01
+ * Merged assertion copying bugfix from Joshua Brindle.
+ * Merged sepol_av_to_string patch from Joshua Brindle.
+
+1.11.10 2006-01-30
+ * Merged cond_expr mapping and package section count bug fixes
+ from Joshua Brindle.
+ * Merged improve port/fcontext API patch from Ivan Gyurdiev.
+ * Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev.
+
+1.11.9 2006-01-12
+ * Merged size_t -> unsigned int patch from Ivan Gyurdiev.
+
+1.11.8 2006-01-09
+ * Merged 2nd const in APIs patch from Ivan Gyurdiev.
+
+1.11.7 2006-01-06
+ * Merged const in APIs patch from Ivan Gyurdiev.
+ * Merged compare2 function patch from Ivan Gyurdiev.
+
+1.11.6 2006-01-06
+ * Fixed hierarchy checker to only check allow rules.
+
+1.11.5 2006-01-05
+ * Merged further fixes from Russell Coker, specifically:
+ - av_to_string overflow checking
+ - sepol_context_to_string error handling
+ - hierarchy checking memory leak fixes and optimizations
+ - avrule_block_read variable initialization
+ * Marked deprecated code in genbools and genusers.
+
+1.11.4 2006-01-05
+ * Merged bugfix for sepol_port_modify from Russell Coker.
+
+1.11.3 2006-01-05
+ * Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev.
+ * Merged port ordering patch from Ivan Gyurdiev.
+
+1.11.2 2006-01-04
+ * Merged patch series from Ivan Gyurdiev.
+ This includes patches to:
+ - support ordering of records in compare function
+ - enable port interfaces
+ - add interfaces for context validity and range checks
+ - add include guards
+
+1.11.1 2005-12-16
+ * Fixed mls_range_cpy bug.
+
+1.10 2005-12-07
+ * Updated version for release.
+
+1.9.42 2005-12-05
+ * Dropped handle from user_del_role interface.
+
+1.9.41 2005-11-28
+ * Merged remove defrole from sepol patch from Ivan Gyurdiev.
+
+1.9.40 2005-11-15
+ * Merged module function and map file cleanup from Ivan Gyurdiev.
+ * Merged MLS and genusers cleanups from Ivan Gyurdiev.
+
+1.9.39 2005-11-09
+ Prepare for removal of booleans* and *.users files.
+ * Cleaned up sepol_genbools to not regenerate the image if
+ there were no changes in the boolean values, including the
+ degenerate case where there are no booleans or booleans.local
+ files.
+ * Cleaned up sepol_genusers to not warn on missing local.users.
+
+1.9.38 2005-11-08
+ * Removed sepol_port_* from libsepol.map, as the port interfaces
+ are not yet stable.
+
+1.9.37 2005-11-04
+ * Merged context destroy cleanup patch from Ivan Gyurdiev.
+
+1.9.36 2005-11-03
+ * Merged context_to_string interface change patch from Ivan Gyurdiev.
+
+1.9.35 2005-11-01
+ * Added src/dso.h and src/*_internal.h.
+ Added hidden_def for exported symbols used within libsepol.
+ Added hidden for symbols that should not be exported by
+ the wildcards in libsepol.map.
+
+1.9.34 2005-10-31
+ * Merged record interface, record bugfix, and set_roles patches
+ from Ivan Gyurdiev.
+
+1.9.33 2005-10-27
+ * Merged count specification change from Ivan Gyurdiev.
+
+1.9.32 2005-10-26
+ * Added further checking and error reporting to
+ sepol_module_package_read and _info.
+
+1.9.31 2005-10-26
+ * Merged sepol handle passing, DEBUG conversion, and memory leak
+ fix patches from Ivan Gyurdiev.
+
+1.9.30 2005-10-25
+ * Removed processing of system.users from sepol_genusers and
+ dropped delusers logic.
+
+1.9.29 2005-10-25
+ * Removed policydb_destroy from error path of policydb_read,
+ since create/init/destroy/free of policydb is handled by the
+ caller now.
+ * Fixed sepol_module_package_read to handle a failed policydb_read
+ properly.
+
+1.9.28 2005-10-25
+ * Merged query/exists and count patches from Ivan Gyurdiev.
+
+1.9.27 2005-10-25
+ * Merged fix for pruned types in expand code from Joshua Brindle.
+ * Merged new module package format code from Joshua Brindle.
+
+1.9.26 2005-10-24
+ * Merged context interface cleanup, record conversion code,
+ key passing, and bug fix patches from Ivan Gyurdiev.
+
+1.9.25 2005-10-21
+ * Merged users cleanup patch from Ivan Gyurdiev.
+
+1.9.24 2005-10-21
+ * Merged user record memory leak fix from Ivan Gyurdiev.
+ * Merged reorganize users patch from Ivan Gyurdiev.
+
+1.9.23 2005-10-19
+ * Added check flag to expand_module() to control assertion
+ and hierarchy checking on expansion.
+
+1.9.22 2005-10-19
+ * Reworked check_assertions() and hierarchy_check_constraints()
+ to take handles and use callback-based error reporting.
+ * Changed expand_module() to call check_assertions() and
+ hierarchy_check_constraints() prior to returning the expanded
+ policy.
+
+1.9.21 2005-10-18
+ * Changed sepol_module_package_set_file_contexts to copy the
+ file contexts data since it is internally managed.
+
+1.9.20 2005-10-18
+ * Added sepol_policy_file_set_handle interface to associate
+ a handle with a policy file.
+ * Added handle argument to policydb_from_image/to_image.
+ * Added sepol_module_package_set_file_contexts interface.
+ * Dropped sepol_module_package_create_file interface.
+ * Reworked policydb_read/write, policydb_from_image/to_image,
+ and sepol_module_package_read/write to use callback-based error
+ reporting system rather than DEBUG.
+
+1.9.19 2005-10-17
+ * Reworked link_packages, link_modules, and expand_module to use
+ callback-based error reporting system rather than error buffering.
+
+1.9.18 2005-10-14
+ * Merged conditional expression mapping fix in the module linking
+ code from Joshua Brindle.
+
+1.9.17 2005-10-13
+ * Hid sepol_module_package type definition, and added get interfaces.
+
+1.9.16 2005-10-13
+ * Merged new callback-based error reporting system from Ivan
+ Gyurdiev.
+
+1.9.15 2005-10-13
+ * Merged support for require blocks inside conditionals from
+ Joshua Brindle (Tresys).
+
+1.9.14 2005-10-07
+ * Fixed use of policydb_from_image/to_image to ensure proper
+ init of policydb.
+
+1.9.13 2005-10-07
+ * Isolated policydb internal headers under <sepol/policydb/*.h>.
+ These headers should only be used by users of the static libsepol.
+ Created new <sepol/policydb.h> with new public types and interfaces
+ for shared libsepol.
+ Created new <sepol/module.h> with public types and interfaces moved
+ or wrapped from old module.h, link.h, and expand.h, adjusted for
+ new public types for policydb and policy_file.
+ Added public interfaces to libsepol.map.
+ Some implementation changes visible to users of the static libsepol:
+ 1) policydb_read no longer calls policydb_init.
+ Caller must do so first.
+ 2) policydb_init no longer takes policy_type argument.
+ Caller must set policy_type separately.
+ 3) expand_module automatically enables the global branch.
+ Caller no longer needs to do so.
+ 4) policydb_write uses the policy_type and policyvers from the
+ policydb itself, and sepol_set_policyvers() has been removed.
+
+1.9.12 2005-10-06
+ * Merged function renaming and static cleanup from Ivan Gyurdiev.
+
+1.9.11 2005-10-05
+ * Merged bug fix for check_assertions handling of no assertions
+ from Joshua Brindle (Tresys).
+
+1.9.10 2005-10-04
+ * Merged iterate patch from Ivan Gyurdiev.
+
+1.9.9 2005-10-03
+ * Merged MLS in modules patch from Joshua Brindle (Tresys).
+
+1.9.8 2005-09-30
+ * Merged pointer typedef elimination patch from Ivan Gyurdiev.
+ * Merged user list function, new mls functions, and bugfix patch
+ from Ivan Gyurdiev.
+
+1.9.7 2005-09-28
+ * Merged sepol_get_num_roles fix from Karl MacMillan (Tresys).
+
+1.9.6 2005-09-23
+ * Merged bug fix patches from Joshua Brindle (Tresys).
+
+1.9.5 2005-09-21
+ * Merged boolean record and memory leak fix patches from Ivan
+ Gyurdiev.
+
+1.9.4 2005-09-19
+ * Merged interface record patch from Ivan Gyurdiev.
+
+1.9.3 2005-09-14
+ * Merged fix for sepol_enable/disable_debug from Ivan
+ Gyurdiev.
+
+1.9.2 2005-09-14
+ * Merged stddef.h patch and debug conversion patch from
+ Ivan Gyurdiev.
+
+1.9.1 2005-09-09
+ * Fixed expand_avtab and expand_cond_av_list to keep separate
+ entries with identical keys but different enabled flags.
+
+1.8 2005-09-06
+ * Updated version for release.
+
+1.7.24 2005-08-31
+ * Fixed symtab_insert return value for duplicate declarations.
+
+1.7.23 2005-08-31
+ * Merged fix for memory error in policy_module_destroy from
+ Jason Tang (Tresys).
+
+1.7.22 2005-08-26
+ * Merged fix for memory leak in sepol_context_to_sid from
+ Jason Tang (Tresys).
+
+1.7.21 2005-08-25
+ * Merged fixes for resource leaks on error paths and
+ change to scope_destroy from Joshua Brindle (Tresys).
+
+1.7.20 2005-08-23
+ * Merged more fixes for resource leaks on error paths
+ from Serge Hallyn (IBM). Bugs found by Coverity.
+
+1.7.19 2005-08-19
+ * Changed to treat all type conflicts as fatal errors.
+
+1.7.18 2005-08-18
+ * Merged several error handling fixes from
+ Serge Hallyn (IBM). Bugs found by Coverity.
+
+1.7.17 2005-08-15
+ * Fixed further memory leaks found by valgrind.
+
+1.7.16 2005-08-15
+ * Fixed several memory leaks found by valgrind.
+
+1.7.15 2005-08-12
+ * Fixed empty list test in cond_write_av_list. Bug found by
+ Coverity, reported by Serge Hallyn (IBM).
+ * Merged patch to policydb_write to check errors
+ when writing the type->attribute reverse map from
+ Serge Hallyn (IBM). Bug found by Coverity.
+ * Fixed policydb_destroy to properly handle NULL type_attr_map
+ or attr_type_map.
+
+1.7.14 2005-08-12
+ * Fixed use of uninitialized data by expand_avtab_node by
+ clearing type_val_to_struct in policydb_index_others.
+
+1.7.13 2005-08-11
+ * Improved memory use by SELinux by both reducing the avtab
+ node size and reducing the number of avtab nodes (by not
+ expanding attributes in TE rules when possible). Added
+ expand_avtab and expand_cond_av_list functions for use by
+ assertion checker, hierarchy checker, compatibility code,
+ and dispol. Added new inline ebitmap operators and converted
+ existing users of ebitmaps to the new operators for greater
+ efficiency.
+ Note: The binary policy format version has been incremented to
+ version 20 as a result of these changes.
+
+1.7.12 2005-08-10
+ * Fixed bug in constraint_node_clone handling of name sets.
+
+1.7.11 2005-08-08
+ * Fix range_trans_clone to map the type values properly.
+
+1.7.10 2005-08-02
+ * Merged patch to move module read/write code from libsemanage
+ to libsepol from Jason Tang (Tresys).
+
+1.7.9 2005-08-02
+ * Enabled further compiler warning flags and fixed them.
+
+1.7.8 2005-08-02
+ * Merged user, context, port records patch from Ivan Gyurdiev.
+ * Merged key extract function patch from Ivan Gyurdiev.
+
+1.7.7 2005-07-27
+ * Merged mls_context_to_sid bugfix from Ivan Gyurdiev.
+
+1.7.6 2005-07-26
+ * Merged context reorganization, memory leak fixes,
+ port and interface loading, replacements for genusers and
+ genbools, debug traceback, and bugfix patches from Ivan Gyurdiev.
+ * Merged uninitialized variable bugfix from Dan Walsh.
+
+1.7.5 2005-07-18
+ * Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat).
+ * Removed genpolbools and genpolusers utilities.
+
+1.7.4 2005-07-18
+ * Merged hierarchy check fix from Joshua Brindle (Tresys).
+
+1.7.3 2005-07-13
+ * Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat).
+
+1.7.2 2005-07-11
+ * Merged genbools debugging message cleanup from Red Hat.
+
+1.7.1 2005-07-06
+ * Merged loadable module support from Tresys Technology.
+
+1.6 2005-06-20
+ * Updated version for release.
+
+1.5.10 2005-05-19
+ * License changed to LGPL v2.1, see COPYING.
+
+1.5.9 2005-05-16
+ * Added sepol_genbools_policydb and sepol_genusers_policydb for
+ audit2why.
+
+1.5.8 2005-05-13
+ * Added sepol_ prefix to Flask types to avoid
+ namespace collision with libselinux.
+
+1.5.7 2005-05-13
+ * Added sepol_compute_av_reason() for audit2why.
+
+1.5.6 2005-04-25
+ * Fixed bug in role hierarchy checker.
+
+1.5.5 2005-04-13
+ * Merged hierarchical type/role patch from Tresys Technology.
+ * Merged MLS fixes from Darrel Goeddel of TCS.
+
+1.5.4 2005-04-13
+ * Changed sepol_genusers to not delete users by default,
+ and added a sepol_set_delusers function to enable deletion.
+ Also, removed special case handling of system_u and user_u.
+
+1.5.3 2005-03-29
+ * Merged booleans.local patch from Dan Walsh.
+
+1.5.2 2005-03-16
+ * Added man page for sepol_check_context.
+
+1.5.1 2005-03-15
+ * Added man page for sepol_genusers function.
+ * Merged man pages for genpolusers and chkcon from Manoj Srivastava.
+
+1.4 2005-03-09
+ * Updated version for release.
+
+1.3.8 2005-03-08
+ * Cleaned up error handling in sepol_genusers and sepol_genbools.
+
+1.3.7 2005-02-28
+ * Merged sepol_debug and fclose patch from Dan Walsh.
+
+1.3.6 2005-02-22
+ * Changed sepol_genusers to also use getline and correctly handle
+ EOL.
+
+1.3.5 2005-02-17
+ * Merged range_transition support from Darrel Goeddel (TCS).
+
+1.3.4 2005-02-16
+ * Added sepol_genusers function.
+
+1.3.3 2005-02-14
+ * Merged endianness and compute_av patches from Darrel Goeddel (TCS).
+
+1.3.2 2005-02-09
+ * Changed relabel Makefile target to use restorecon.
+
+1.3.1 2005-01-26
+ * Merged enhanced MLS support from Darrel Goeddel (TCS).
+
+1.2.1 2005-01-19
+ * Merged build fix patch from Manoj Srivastava.
+
+1.2 2004-10-07
+ * MLS build fixes.
+ * Added sepol_set_policydb_from_file and sepol_check_context for setfiles.
+
+1.0 2004-08-19
+ * Initial public release.
+
+0.4 2004-08-13
+ * Merged patch from Dan Walsh to ignore case on booleans.
+ * Changed sepol_genbools* to preserve the original policy version.
+ * Replaced exported global variables with set functions.
+ * Moved genpolbools utility from checkpolicy to libsepol.
+ * Added man pages for sepol_genbools* and genpolbools.
+
+0.3 2004-08-10
+ * Added ChangeLog, COPYING, spec file.
+ * Added sepol_genbools_array() for load_policy.
+ * Created libsepol.map to limit exported symbols in shared library.
+
+0.2 2004-08-09
+ * Exported other functions for checkpolicy and friends.
+ * Renamed service and sidtab functions to avoid libselinux conflict.
+ * Removed original code from checkpolicy, which now uses libsepol.
+ * Code cleanup: kill legacy references to kernel types/functions.
+
+0.1 2004-08-06
+ * Moved checkpolicy core logic into a library.
+ * Exported sepol_genbools() for load_policy.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d526965
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+all:
+ $(MAKE) -C src
+ $(MAKE) -C utils
+
+install:
+ $(MAKE) -C include install
+ $(MAKE) -C src install
+ $(MAKE) -C utils install
+ $(MAKE) -C man install
+
+relabel:
+ $(MAKE) -C src relabel
+
+clean:
+ $(MAKE) -C src clean
+ $(MAKE) -C utils clean
+ $(MAKE) -C tests clean
+
+indent:
+ $(MAKE) -C src $@
+ $(MAKE) -C include $@
+ $(MAKE) -C utils $@
+
+test:
+ $(MAKE) -C tests test
+
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..7ec1d6d
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+2.1.0
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 0000000..0cd00ab
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,12 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCDIR ?= $(PREFIX)/include/sepol
+
+install:
+ test -d $(INCDIR) || install -m 755 -d $(INCDIR)
+ test -d $(INCDIR)/policydb || install -m 755 -d $(INCDIR)/policydb
+ install -m 644 $(wildcard sepol/*.h) $(INCDIR)
+ install -m 644 $(wildcard sepol/policydb/*.h) $(INCDIR)/policydb
+
+indent:
+ ../../scripts/Lindent $(wildcard sepol/*.h)
diff --git a/include/sepol/boolean_record.h b/include/sepol/boolean_record.h
new file mode 100644
index 0000000..54ca021
--- /dev/null
+++ b/include/sepol/boolean_record.h
@@ -0,0 +1,51 @@
+#ifndef _SEPOL_BOOLEAN_RECORD_H_
+#define _SEPOL_BOOLEAN_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+
+struct sepol_bool;
+struct sepol_bool_key;
+typedef struct sepol_bool sepol_bool_t;
+typedef struct sepol_bool_key sepol_bool_key_t;
+
+/* Key */
+extern int sepol_bool_key_create(sepol_handle_t * handle,
+ const char *name, sepol_bool_key_t ** key);
+
+extern void sepol_bool_key_unpack(const sepol_bool_key_t * key,
+ const char **name);
+
+extern int sepol_bool_key_extract(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_key_t ** key_ptr);
+
+extern void sepol_bool_key_free(sepol_bool_key_t * key);
+
+extern int sepol_bool_compare(const sepol_bool_t * boolean,
+ const sepol_bool_key_t * key);
+
+extern int sepol_bool_compare2(const sepol_bool_t * boolean,
+ const sepol_bool_t * boolean2);
+
+/* Name */
+extern const char *sepol_bool_get_name(const sepol_bool_t * boolean);
+
+extern int sepol_bool_set_name(sepol_handle_t * handle,
+ sepol_bool_t * boolean, const char *name);
+
+/* Value */
+extern int sepol_bool_get_value(const sepol_bool_t * boolean);
+
+extern void sepol_bool_set_value(sepol_bool_t * boolean, int value);
+
+/* Create/Clone/Destroy */
+extern int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr);
+
+extern int sepol_bool_clone(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_t ** bool_ptr);
+
+extern void sepol_bool_free(sepol_bool_t * boolean);
+
+#endif
diff --git a/include/sepol/booleans.h b/include/sepol/booleans.h
new file mode 100644
index 0000000..95ee7de
--- /dev/null
+++ b/include/sepol/booleans.h
@@ -0,0 +1,59 @@
+#ifndef _SEPOL_BOOLEANS_H_
+#define _SEPOL_BOOLEANS_H_
+
+#include <stddef.h>
+#include <sepol/policydb.h>
+#include <sepol/boolean_record.h>
+#include <sepol/handle.h>
+
+/*--------------compatibility--------------*/
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+ and a boolean configuration file named by 'boolpath', rewrite the binary
+ policy for the boolean settings in the boolean configuration file.
+ The binary policy is rewritten in place in memory.
+ Returns 0 upon success, or -1 otherwise. */
+extern int sepol_genbools(void *data, size_t len, char *boolpath);
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+ and boolean settings specified by the parallel arrays ('names', 'values')
+ with 'nel' elements, rewrite the binary policy for the boolean settings.
+ The binary policy is rewritten in place in memory.
+ Returns 0 upon success or -1 otherwise. */
+extern int sepol_genbools_array(void *data, size_t len,
+ char **names, int *values, int nel);
+/*---------------end compatbility------------*/
+
+/* Set the specified boolean */
+extern int sepol_bool_set(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_bool_key_t * key,
+ const sepol_bool_t * data);
+
+/* Return the number of booleans */
+extern int sepol_bool_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified boolean exists */
+extern int sepol_bool_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_bool_key_t * key, int *response);
+
+/* Query a boolean - returns the boolean, or NULL if not found */
+extern int sepol_bool_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key,
+ sepol_bool_t ** response);
+
+/* Iterate the booleans
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_bool_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_bool_t * boolean,
+ void *fn_arg), void *arg);
+
+#endif
diff --git a/include/sepol/context.h b/include/sepol/context.h
new file mode 100644
index 0000000..c1eadca
--- /dev/null
+++ b/include/sepol/context.h
@@ -0,0 +1,25 @@
+#ifndef _SEPOL_CONTEXT_H_
+#define _SEPOL_CONTEXT_H_
+
+#include <sepol/context_record.h>
+#include <sepol/policydb.h>
+#include <sepol/handle.h>
+
+/* -- Deprecated -- */
+
+extern int sepol_check_context(const char *context);
+
+/* -- End deprecated -- */
+
+extern int sepol_context_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_context_t * context);
+
+extern int sepol_mls_contains(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const char *mls1,
+ const char *mls2, int *response);
+
+extern int sepol_mls_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb, const char *mls);
+#endif
diff --git a/include/sepol/context_record.h b/include/sepol/context_record.h
new file mode 100644
index 0000000..c305480
--- /dev/null
+++ b/include/sepol/context_record.h
@@ -0,0 +1,53 @@
+#ifndef _SEPOL_CONTEXT_RECORD_H_
+#define _SEPOL_CONTEXT_RECORD_H_
+
+#include <sepol/handle.h>
+
+struct sepol_context;
+typedef struct sepol_context sepol_context_t;
+
+/* We don't need a key, because the context is never stored
+ * in a data collection by itself */
+
+/* User */
+extern const char *sepol_context_get_user(const sepol_context_t * con);
+
+extern int sepol_context_set_user(sepol_handle_t * handle,
+ sepol_context_t * con, const char *user);
+
+/* Role */
+extern const char *sepol_context_get_role(const sepol_context_t * con);
+
+extern int sepol_context_set_role(sepol_handle_t * handle,
+ sepol_context_t * con, const char *role);
+
+/* Type */
+extern const char *sepol_context_get_type(const sepol_context_t * con);
+
+extern int sepol_context_set_type(sepol_handle_t * handle,
+ sepol_context_t * con, const char *type);
+
+/* MLS */
+extern const char *sepol_context_get_mls(const sepol_context_t * con);
+
+extern int sepol_context_set_mls(sepol_handle_t * handle,
+ sepol_context_t * con, const char *mls_range);
+
+/* Create/Clone/Destroy */
+extern int sepol_context_create(sepol_handle_t * handle,
+ sepol_context_t ** con_ptr);
+
+extern int sepol_context_clone(sepol_handle_t * handle,
+ const sepol_context_t * con,
+ sepol_context_t ** con_ptr);
+
+extern void sepol_context_free(sepol_context_t * con);
+
+/* Parse to/from string */
+extern int sepol_context_from_string(sepol_handle_t * handle,
+ const char *str, sepol_context_t ** con);
+
+extern int sepol_context_to_string(sepol_handle_t * handle,
+ const sepol_context_t * con, char **str_ptr);
+
+#endif
diff --git a/include/sepol/debug.h b/include/sepol/debug.h
new file mode 100644
index 0000000..3370845
--- /dev/null
+++ b/include/sepol/debug.h
@@ -0,0 +1,34 @@
+#ifndef _SEPOL_DEBUG_H_
+#define _SEPOL_DEBUG_H_
+
+#include <sepol/handle.h>
+
+/* Deprecated */
+extern void sepol_debug(int on);
+/* End deprecated */
+
+#define SEPOL_MSG_ERR 1
+#define SEPOL_MSG_WARN 2
+#define SEPOL_MSG_INFO 3
+
+extern int sepol_msg_get_level(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_channel(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_fname(sepol_handle_t * handle);
+
+/* Set the messaging callback.
+ * By the default, the callback will print
+ * the message on standard output, in a
+ * particular format. Passing NULL here
+ * indicates that messaging should be suppressed */
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t *
+ handle,
+ const char *fmt, ...),
+ void *msg_callback_arg);
+#endif
diff --git a/include/sepol/errcodes.h b/include/sepol/errcodes.h
new file mode 100644
index 0000000..c6f3a8b
--- /dev/null
+++ b/include/sepol/errcodes.h
@@ -0,0 +1,25 @@
+/* Author: Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_errno_h__
+#define __sepol_errno_h__
+
+#include <errno.h>
+
+#define SEPOL_OK 0
+
+/* These first error codes are defined for compatibility with
+ * previous version of libsepol. In the future, custome error
+ * codes that don't map to system error codes should be defined
+ * outside of the range of system error codes.
+ */
+#define SEPOL_ERR -1
+#define SEPOL_ENOTSUP -2 /* feature not supported in module language */
+#define SEPOL_EREQ -3 /* requirements not met */
+
+/* Error codes that map to system error codes */
+#define SEPOL_ENOMEM -ENOMEM
+#define SEPOL_ERANGE -ERANGE
+#define SEPOL_EEXIST -EEXIST
+#define SEPOL_ENOENT -ENOENT
+
+#endif
diff --git a/include/sepol/handle.h b/include/sepol/handle.h
new file mode 100644
index 0000000..19be326
--- /dev/null
+++ b/include/sepol/handle.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_HANDLE_H_
+#define _SEPOL_HANDLE_H_
+
+struct sepol_handle;
+typedef struct sepol_handle sepol_handle_t;
+
+/* Create and return a sepol handle. */
+sepol_handle_t *sepol_handle_create(void);
+
+/* Get whether or not dontaudits will be disabled, same values as
+ * specified by set_disable_dontaudit. This value reflects the state
+ * your system will be set to upon commit, not necessarily its
+ * current state.*/
+int sepol_get_disable_dontaudit(sepol_handle_t * sh);
+
+/* Set whether or not to disable dontaudits, 0 is default and does
+ * not disable dontaudits, 1 disables them */
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit);
+
+/* Set whether module_expand() should consume the base policy passed in.
+ * This should reduce the amount of memory required to expand the policy. */
+void sepol_set_expand_consume_base(sepol_handle_t * sh, int consume_base);
+
+/* Destroy a sepol handle. */
+void sepol_handle_destroy(sepol_handle_t *);
+
+#endif
diff --git a/include/sepol/iface_record.h b/include/sepol/iface_record.h
new file mode 100644
index 0000000..a72678c
--- /dev/null
+++ b/include/sepol/iface_record.h
@@ -0,0 +1,59 @@
+#ifndef _SEPOL_IFACE_RECORD_H_
+#define _SEPOL_IFACE_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sepol/context_record.h>
+
+struct sepol_iface;
+struct sepol_iface_key;
+typedef struct sepol_iface sepol_iface_t;
+typedef struct sepol_iface_key sepol_iface_key_t;
+
+/* Key */
+extern int sepol_iface_compare(const sepol_iface_t * iface,
+ const sepol_iface_key_t * key);
+
+extern int sepol_iface_compare2(const sepol_iface_t * iface,
+ const sepol_iface_t * iface2);
+
+extern void sepol_iface_key_unpack(const sepol_iface_key_t * key,
+ const char **name);
+
+extern int sepol_iface_key_create(sepol_handle_t * handle,
+ const char *name,
+ sepol_iface_key_t ** key_ptr);
+
+extern int sepol_iface_key_extract(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_key_t ** key_ptr);
+
+extern void sepol_iface_key_free(sepol_iface_key_t * key);
+
+/* Name */
+extern const char *sepol_iface_get_name(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_name(sepol_handle_t * handle,
+ sepol_iface_t * iface, const char *name);
+
+/* Context */
+extern sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_ifcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con);
+
+extern sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_msgcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_iface_create(sepol_handle_t * handle,
+ sepol_iface_t ** iface_ptr);
+
+extern int sepol_iface_clone(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_t ** iface_ptr);
+
+extern void sepol_iface_free(sepol_iface_t * iface);
+
+#endif
diff --git a/include/sepol/interfaces.h b/include/sepol/interfaces.h
new file mode 100644
index 0000000..9849e13
--- /dev/null
+++ b/include/sepol/interfaces.h
@@ -0,0 +1,43 @@
+#ifndef __SEPOL_INTERFACES_H_
+#define __SEPOL_INTERFACES_H_
+
+#include <sepol/policydb.h>
+#include <sepol/iface_record.h>
+#include <sepol/handle.h>
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ unsigned int *response);
+
+/* Check if an interface exists */
+extern int sepol_iface_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key, int *response);
+
+/* Query an interface - returns the interface,
+ * or NULL if not found */
+extern int sepol_iface_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key,
+ sepol_iface_t ** response);
+
+/* Modify an interface, or add it, if the key
+ * is not found */
+extern int sepol_iface_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key,
+ const sepol_iface_t * data);
+
+/* Iterate the interfaces
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_iface_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_iface_t * iface,
+ void *fn_arg), void *arg);
+
+#endif
diff --git a/include/sepol/module.h b/include/sepol/module.h
new file mode 100644
index 0000000..35f5cb7
--- /dev/null
+++ b/include/sepol/module.h
@@ -0,0 +1,82 @@
+#ifndef _SEPOL_MODULE_H_
+#define _SEPOL_MODULE_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+
+struct sepol_module_package;
+typedef struct sepol_module_package sepol_module_package_t;
+
+/* Module package public interfaces. */
+
+extern int sepol_module_package_create(sepol_module_package_t ** p);
+
+extern void sepol_module_package_free(sepol_module_package_t * p);
+
+extern char *sepol_module_package_get_file_contexts(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t
+ * p);
+
+extern int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_seusers(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_seusers(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_user_extra(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_user_extra_len(sepol_module_package_t *
+ p);
+
+extern int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t
+ * p);
+
+extern size_t
+sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_netfilter_contexts(sepol_module_package_t *
+ p, char *data,
+ size_t len);
+
+extern sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t
+ * p);
+
+extern int sepol_link_packages(sepol_handle_t * handle,
+ sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules, int verbose);
+
+extern int sepol_module_package_read(sepol_module_package_t * mod,
+ struct sepol_policy_file *file,
+ int verbose);
+
+extern int sepol_module_package_info(struct sepol_policy_file *file,
+ int *type, char **name, char **version);
+
+extern int sepol_module_package_write(sepol_module_package_t * p,
+ struct sepol_policy_file *file);
+
+/* Module linking/expanding public interfaces. */
+
+extern int sepol_link_modules(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t ** modules,
+ size_t len, int verbose);
+
+extern int sepol_expand_module(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t * out, int verbose, int check);
+
+#endif
diff --git a/include/sepol/node_record.h b/include/sepol/node_record.h
new file mode 100644
index 0000000..9f61ac7
--- /dev/null
+++ b/include/sepol/node_record.h
@@ -0,0 +1,92 @@
+#ifndef _SEPOL_NODE_RECORD_H_
+#define _SEPOL_NODE_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+
+struct sepol_node;
+struct sepol_node_key;
+typedef struct sepol_node sepol_node_t;
+typedef struct sepol_node_key sepol_node_key_t;
+
+#define SEPOL_PROTO_IP4 0
+#define SEPOL_PROTO_IP6 1
+
+/* Key */
+extern int sepol_node_compare(const sepol_node_t * node,
+ const sepol_node_key_t * key);
+
+extern int sepol_node_compare2(const sepol_node_t * node,
+ const sepol_node_t * node2);
+
+extern int sepol_node_key_create(sepol_handle_t * handle,
+ const char *addr,
+ const char *mask,
+ int proto, sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_unpack(const sepol_node_key_t * key,
+ const char **addr,
+ const char **mask, int *proto);
+
+extern int sepol_node_key_extract(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_free(sepol_node_key_t * key);
+
+/* Address */
+extern int sepol_node_get_addr(sepol_handle_t * handle,
+ const sepol_node_t * node, char **addr);
+
+extern int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **addr, size_t * addr_sz);
+
+extern int sepol_node_set_addr(sepol_handle_t * handle,
+ sepol_node_t * node,
+ int proto, const char *addr);
+
+extern int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *addr, size_t addr_sz);
+
+/* Netmask */
+extern int sepol_node_get_mask(sepol_handle_t * handle,
+ const sepol_node_t * node, char **mask);
+
+extern int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **mask, size_t * mask_sz);
+
+extern int sepol_node_set_mask(sepol_handle_t * handle,
+ sepol_node_t * node,
+ int proto, const char *mask);
+
+extern int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *mask, size_t mask_sz);
+
+/* Protocol */
+extern int sepol_node_get_proto(const sepol_node_t * node);
+
+extern void sepol_node_set_proto(sepol_node_t * node, int proto);
+
+extern const char *sepol_node_get_proto_str(int proto);
+
+/* Context */
+extern sepol_context_t *sepol_node_get_con(const sepol_node_t * node);
+
+extern int sepol_node_set_con(sepol_handle_t * handle,
+ sepol_node_t * node, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node_ptr);
+
+extern int sepol_node_clone(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_t ** node_ptr);
+
+extern void sepol_node_free(sepol_node_t * node);
+
+#endif
diff --git a/include/sepol/nodes.h b/include/sepol/nodes.h
new file mode 100644
index 0000000..1e0ac4f
--- /dev/null
+++ b/include/sepol/nodes.h
@@ -0,0 +1,40 @@
+#ifndef _SEPOL_NODES_H_
+#define _SEPOL_NODES_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/node_record.h>
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a node exists */
+extern int sepol_node_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_node_key_t * key, int *response);
+
+/* Query a node - returns the node, or NULL if not found */
+extern int sepol_node_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_node_key_t * key,
+ sepol_node_t ** response);
+
+/* Modify a node, or add it, if the key is not found */
+extern int sepol_node_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_node_key_t * key,
+ const sepol_node_t * data);
+
+/* Iterate the nodes
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_node_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_node_t * node,
+ void *fn_arg), void *arg);
+
+#endif
diff --git a/include/sepol/policydb.h b/include/sepol/policydb.h
new file mode 100644
index 0000000..43e23b3
--- /dev/null
+++ b/include/sepol/policydb.h
@@ -0,0 +1,138 @@
+#ifndef _SEPOL_POLICYDB_H_
+#define _SEPOL_POLICYDB_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <sepol/handle.h>
+
+struct sepol_policy_file;
+typedef struct sepol_policy_file sepol_policy_file_t;
+
+struct sepol_policydb;
+typedef struct sepol_policydb sepol_policydb_t;
+
+/* Policy file public interfaces. */
+
+/* Create and free memory associated with a policy file. */
+extern int sepol_policy_file_create(sepol_policy_file_t ** pf);
+extern void sepol_policy_file_free(sepol_policy_file_t * pf);
+
+/*
+ * Set the policy file to represent a binary policy memory image.
+ * Subsequent operations using the policy file will read and write
+ * the image located at the specified address with the specified length.
+ * If 'len' is 0, then merely compute the necessary length upon
+ * subsequent policydb write operations in order to determine the
+ * necessary buffer size to allocate.
+ */
+extern void sepol_policy_file_set_mem(sepol_policy_file_t * pf,
+ char *data, size_t len);
+
+/*
+ * Get the size of the buffer needed to store a policydb write
+ * previously done on this policy file.
+ */
+extern int sepol_policy_file_get_len(sepol_policy_file_t * pf, size_t * len);
+
+/*
+ * Set the policy file to represent a FILE.
+ * Subsequent operations using the policy file will read and write
+ * to the FILE.
+ */
+extern void sepol_policy_file_set_fp(sepol_policy_file_t * pf, FILE * fp);
+
+/*
+ * Associate a handle with a policy file, for use in
+ * error reporting from subsequent calls that take the
+ * policy file as an argument.
+ */
+extern void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+ sepol_handle_t * handle);
+
+/* Policydb public interfaces. */
+
+/* Create and free memory associated with a policydb. */
+extern int sepol_policydb_create(sepol_policydb_t ** p);
+extern void sepol_policydb_free(sepol_policydb_t * p);
+
+/* Legal types of policies that the policydb can represent. */
+#define SEPOL_POLICY_KERN 0
+#define SEPOL_POLICY_BASE 1
+#define SEPOL_POLICY_MOD 2
+
+/*
+ * Range of policy versions for the kernel policy type supported
+ * by this library.
+ */
+extern int sepol_policy_kern_vers_min(void);
+extern int sepol_policy_kern_vers_max(void);
+
+/*
+ * Set the policy type as specified, and automatically initialize the
+ * policy version accordingly to the maximum version supported for the
+ * policy type.
+ * Returns -1 if the policy type is not legal.
+ */
+extern int sepol_policydb_set_typevers(sepol_policydb_t * p, unsigned int type);
+
+/*
+ * Set the policy version to a different value.
+ * Returns -1 if the policy version is not in the supported range for
+ * the (previously set) policy type.
+ */
+extern int sepol_policydb_set_vers(sepol_policydb_t * p, unsigned int vers);
+
+/* Set how to handle unknown class/perms. */
+#define SEPOL_DENY_UNKNOWN 0
+#define SEPOL_REJECT_UNKNOWN 2
+#define SEPOL_ALLOW_UNKNOWN 4
+extern int sepol_policydb_set_handle_unknown(sepol_policydb_t * p,
+ unsigned int handle_unknown);
+
+/*
+ * Read a policydb from a policy file.
+ * This automatically sets the type and version based on the
+ * image contents.
+ */
+extern int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Write a policydb to a policy file.
+ * The generated image will be in the binary format corresponding
+ * to the policy version associated with the policydb.
+ */
+extern int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Extract a policydb from a binary policy memory image.
+ * This is equivalent to sepol_policydb_read with a policy file
+ * set to refer to memory.
+ */
+extern int sepol_policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len,
+ sepol_policydb_t * p);
+
+/*
+ * Generate a binary policy memory image from a policydb.
+ * This is equivalent to sepol_policydb_write with a policy file
+ * set to refer to memory, but internally handles computing the
+ * necessary length and allocating an appropriately sized memory
+ * buffer for the caller.
+ */
+extern int sepol_policydb_to_image(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ void **newdata, size_t * newlen);
+
+/*
+ * Check whether the policydb has MLS enabled.
+ */
+extern int sepol_policydb_mls_enabled(const sepol_policydb_t * p);
+
+/*
+ * Check whether the compatibility mode for SELinux network
+ * checks should be enabled when using this policy.
+ */
+extern int sepol_policydb_compat_net(const sepol_policydb_t * p);
+
+#endif
diff --git a/include/sepol/policydb/avrule_block.h b/include/sepol/policydb/avrule_block.h
new file mode 100644
index 0000000..dc926e5
--- /dev/null
+++ b/include/sepol/policydb/avrule_block.h
@@ -0,0 +1,37 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_AVRULE_BLOCK_H_
+#define _SEPOL_AVRULE_BLOCK_H_
+
+#include <sepol/policydb/policydb.h>
+
+extern avrule_block_t *avrule_block_create(void);
+extern void avrule_block_destroy(avrule_block_t * x);
+extern avrule_decl_t *avrule_decl_create(uint32_t decl_id);
+extern void avrule_decl_destroy(avrule_decl_t * x);
+extern void avrule_block_list_destroy(avrule_block_t * x);
+extern avrule_decl_t *get_avrule_decl(policydb_t * p, uint32_t decl_id);
+extern cond_list_t *get_decl_cond_list(policydb_t * p,
+ avrule_decl_t * decl,
+ cond_list_t * cond);
+extern int is_id_enabled(char *id, policydb_t * p, int symbol_table);
+extern int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p);
+
+#endif
diff --git a/include/sepol/policydb/avtab.h b/include/sepol/policydb/avtab.h
new file mode 100644
index 0000000..6955ecf
--- /dev/null
+++ b/include/sepol/policydb/avtab.h
@@ -0,0 +1,127 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * An access vector table (avtab) is a hash table
+ * of access vectors and transition types indexed
+ * by a type pair and a class. An access vector
+ * table is used to represent the type enforcement
+ * tables.
+ */
+
+#ifndef _SEPOL_POLICYDB_AVTAB_H_
+#define _SEPOL_POLICYDB_AVTAB_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+typedef struct avtab_key {
+ uint16_t source_type;
+ uint16_t target_type;
+ uint16_t target_class;
+#define AVTAB_ALLOWED 1
+#define AVTAB_AUDITALLOW 2
+#define AVTAB_AUDITDENY 4
+#define AVTAB_NEVERALLOW 128
+#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 16
+#define AVTAB_MEMBER 32
+#define AVTAB_CHANGE 64
+#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_ENABLED_OLD 0x80000000
+#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
+ uint16_t specified; /* what fields are specified */
+} avtab_key_t;
+
+typedef struct avtab_datum {
+ uint32_t data; /* access vector or type */
+} avtab_datum_t;
+
+typedef struct avtab_node *avtab_ptr_t;
+
+struct avtab_node {
+ avtab_key_t key;
+ avtab_datum_t datum;
+ avtab_ptr_t next;
+ void *parse_context; /* generic context pointer used by parser;
+ * not saved in binary policy */
+ unsigned merged; /* flag for avtab_write only;
+ not saved in binary policy */
+};
+
+typedef struct avtab {
+ avtab_ptr_t *htable;
+ uint32_t nel; /* number of elements */
+ uint32_t nslot; /* number of hash slots */
+ uint16_t mask; /* mask to compute hash func */
+} avtab_t;
+
+extern int avtab_init(avtab_t *);
+extern int avtab_alloc(avtab_t *, uint32_t);
+extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
+
+extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
+
+extern void avtab_destroy(avtab_t * h);
+
+extern int avtab_map(avtab_t * h,
+ int (*apply) (avtab_key_t * k,
+ avtab_datum_t * d, void *args), void *args);
+
+extern void avtab_hash_eval(avtab_t * h, char *tag);
+
+struct policy_file;
+extern int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+ int (*insert) (avtab_t * a, avtab_key_t * k,
+ avtab_datum_t * d, void *p), void *p);
+
+extern int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers);
+
+extern avtab_ptr_t avtab_insert_nonunique(avtab_t * h, avtab_key_t * key,
+ avtab_datum_t * datum);
+
+extern avtab_ptr_t avtab_insert_with_parse_context(avtab_t * h,
+ avtab_key_t * key,
+ avtab_datum_t * datum,
+ void *parse_context);
+
+extern avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key);
+
+extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
+
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
+
+#endif /* _AVTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/conditional.h b/include/sepol/policydb/conditional.h
new file mode 100644
index 0000000..a8ed694
--- /dev/null
+++ b/include/sepol/policydb/conditional.h
@@ -0,0 +1,134 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ * Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_CONDITIONAL_H_
+#define _SEPOL_POLICYDB_CONDITIONAL_H_
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/policydb.h>
+
+#define COND_EXPR_MAXDEPTH 10
+
+/* this is the max unique bools in a conditional expression
+ * for which we precompute all outcomes for the expression.
+ *
+ * NOTE - do _NOT_ use value greater than 5 because
+ * cond_node_t->expr_pre_comp can only hold at most 32 values
+ */
+#define COND_MAX_BOOLS 5
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+typedef struct cond_expr {
+#define COND_BOOL 1 /* plain bool */
+#define COND_NOT 2 /* !bool */
+#define COND_OR 3 /* bool || bool */
+#define COND_AND 4 /* bool && bool */
+#define COND_XOR 5 /* bool ^ bool */
+#define COND_EQ 6 /* bool == bool */
+#define COND_NEQ 7 /* bool != bool */
+#define COND_LAST COND_NEQ
+ uint32_t expr_type;
+ uint32_t bool;
+ struct cond_expr *next;
+} cond_expr_t;
+
+/*
+ * Each cond_node_t contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This
+ * struct is for that list.
+ */
+typedef struct cond_av_list {
+ avtab_ptr_t node;
+ struct cond_av_list *next;
+} cond_av_list_t;
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+typedef struct cond_node {
+ int cur_state;
+ cond_expr_t *expr;
+ /* these true/false lists point into te_avtab when that is used */
+ cond_av_list_t *true_list;
+ cond_av_list_t *false_list;
+ /* and these are using during parsing and for modules */
+ avrule_t *avtrue_list;
+ avrule_t *avfalse_list;
+ /* these fields are not written to binary policy */
+ unsigned int nbools;
+ uint32_t bool_ids[COND_MAX_BOOLS];
+ uint32_t expr_pre_comp;
+ /* */
+ struct cond_node *next;
+} cond_node_t;
+
+extern int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr);
+extern cond_expr_t *cond_copy_expr(cond_expr_t * expr);
+
+extern int cond_expr_equal(cond_node_t * a, cond_node_t * b);
+extern int cond_normalize_expr(policydb_t * p, cond_node_t * cn);
+extern void cond_node_destroy(cond_node_t * node);
+extern void cond_expr_destroy(cond_expr_t * expr);
+
+extern cond_node_t *cond_node_find(policydb_t * p,
+ cond_node_t * needle, cond_node_t * haystack,
+ int *was_created);
+
+extern cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node);
+
+extern cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+ cond_node_t * cn);
+
+extern int evaluate_conds(policydb_t * p);
+
+extern avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+ cond_av_list_t * cond_list);
+
+extern void cond_av_list_destroy(cond_av_list_t * list);
+
+extern void cond_optimize_lists(cond_list_t * cl);
+
+extern int cond_policydb_init(policydb_t * p);
+extern void cond_policydb_destroy(policydb_t * p);
+extern void cond_list_destroy(cond_list_t * list);
+
+extern int cond_init_bool_indexes(policydb_t * p);
+extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
+
+extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum,
+ void *datap);
+
+extern int cond_read_bool(policydb_t * p, hashtab_t h, struct policy_file *fp);
+
+extern int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp);
+
+extern void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+ struct sepol_av_decision *avd);
+
+#endif /* _CONDITIONAL_H_ */
diff --git a/include/sepol/policydb/constraint.h b/include/sepol/policydb/constraint.h
new file mode 100644
index 0000000..4c16ab0
--- /dev/null
+++ b/include/sepol/policydb/constraint.h
@@ -0,0 +1,77 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A constraint is a condition that must be satisfied in
+ * order for one or more permissions to be granted.
+ * Constraints are used to impose additional restrictions
+ * beyond the type-based rules in `te' or the role-based
+ * transition rules in `rbac'. Constraints are typically
+ * used to prevent a process from transitioning to a new user
+ * identity or role unless it is in a privileged type.
+ * Constraints are likewise typically used to prevent a
+ * process from labeling an object with a different user
+ * identity.
+ */
+
+#ifndef _SEPOL_POLICYDB_CONSTRAINT_H_
+#define _SEPOL_POLICYDB_CONSTRAINT_H_
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+
+#define CEXPR_MAXDEPTH 5
+
+struct type_set;
+
+typedef struct constraint_expr {
+#define CEXPR_NOT 1 /* not expr */
+#define CEXPR_AND 2 /* expr and expr */
+#define CEXPR_OR 3 /* expr or expr */
+#define CEXPR_ATTR 4 /* attr op attr */
+#define CEXPR_NAMES 5 /* attr op names */
+ uint32_t expr_type; /* expression type */
+
+#define CEXPR_USER 1 /* user */
+#define CEXPR_ROLE 2 /* role */
+#define CEXPR_TYPE 4 /* type */
+#define CEXPR_TARGET 8 /* target if set, source otherwise */
+#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
+ uint32_t attr; /* attribute */
+
+#define CEXPR_EQ 1 /* == or eq */
+#define CEXPR_NEQ 2 /* != */
+#define CEXPR_DOM 3 /* dom */
+#define CEXPR_DOMBY 4 /* domby */
+#define CEXPR_INCOMP 5 /* incomp */
+ uint32_t op; /* operator */
+
+ ebitmap_t names; /* names */
+ struct type_set *type_names;
+
+ struct constraint_expr *next; /* next expression */
+} constraint_expr_t;
+
+typedef struct constraint_node {
+ sepol_access_vector_t permissions; /* constrained permissions */
+ constraint_expr_t *expr; /* constraint on permissions */
+ struct constraint_node *next; /* next constraint */
+} constraint_node_t;
+
+struct policydb;
+
+extern int constraint_expr_init(constraint_expr_t * expr);
+extern void constraint_expr_destroy(constraint_expr_t * expr);
+
+#endif /* _CONSTRAINT_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/context.h b/include/sepol/policydb/context.h
new file mode 100644
index 0000000..8d74a25
--- /dev/null
+++ b/include/sepol/policydb/context.h
@@ -0,0 +1,97 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy. Security contexts are
+ * externally represented as variable-length strings
+ * that can be interpreted by a user or application
+ * with an understanding of the security policy.
+ * Internally, the security server uses a simple
+ * structure. This structure is private to the
+ * security server and can be changed without affecting
+ * clients of the security server.
+ */
+
+#ifndef _SEPOL_POLICYDB_CONTEXT_H_
+#define _SEPOL_POLICYDB_CONTEXT_H_
+
+#include <stddef.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/mls_types.h>
+
+/*
+ * A security context consists of an authenticated user
+ * identity, a role, a type and a MLS range.
+ */
+typedef struct context_struct {
+ uint32_t user;
+ uint32_t role;
+ uint32_t type;
+ mls_range_t range;
+} context_struct_t;
+
+static inline void mls_context_init(context_struct_t * c)
+{
+ mls_range_init(&c->range);
+}
+
+static inline int mls_context_cpy(context_struct_t * dst,
+ context_struct_t * src)
+{
+
+ if (mls_range_cpy(&dst->range, &src->range) < 0)
+ return -1;
+
+ return 0;
+}
+
+static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+ return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) &&
+ mls_level_eq(&c1->range.level[1], &c2->range.level[1]));
+
+}
+
+static inline void mls_context_destroy(context_struct_t * c)
+{
+ if (c == NULL)
+ return;
+
+ mls_range_destroy(&c->range);
+ mls_context_init(c);
+}
+
+static inline void context_init(context_struct_t * c)
+{
+ memset(c, 0, sizeof(*c));
+}
+
+static inline int context_cpy(context_struct_t * dst, context_struct_t * src)
+{
+ dst->user = src->user;
+ dst->role = src->role;
+ dst->type = src->type;
+ return mls_context_cpy(dst, src);
+}
+
+static inline void context_destroy(context_struct_t * c)
+{
+ if (c == NULL)
+ return;
+
+ c->user = c->role = c->type = 0;
+ mls_context_destroy(c);
+}
+
+static inline int context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+ return ((c1->user == c2->user) &&
+ (c1->role == c2->role) &&
+ (c1->type == c2->type) && mls_context_cmp(c1, c2));
+}
+
+#endif
diff --git a/include/sepol/policydb/ebitmap.h b/include/sepol/policydb/ebitmap.h
new file mode 100644
index 0000000..410c15c
--- /dev/null
+++ b/include/sepol/policydb/ebitmap.h
@@ -0,0 +1,88 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * An extensible bitmap is a bitmap that supports an
+ * arbitrary number of bits. Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ */
+
+#ifndef _SEPOL_POLICYDB_EBITMAP_H_
+#define _SEPOL_POLICYDB_EBITMAP_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#define MAPTYPE uint64_t /* portion of bitmap in each node */
+#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
+#define MAPBIT 1ULL /* a bit in the node bitmap */
+
+typedef struct ebitmap_node {
+ uint32_t startbit; /* starting position in the total bitmap */
+ MAPTYPE map; /* this node's portion of the bitmap */
+ struct ebitmap_node *next;
+} ebitmap_node_t;
+
+typedef struct ebitmap {
+ ebitmap_node_t *node; /* first node in the bitmap */
+ uint32_t highbit; /* highest position in the total bitmap */
+} ebitmap_t;
+
+#define ebitmap_length(e) ((e)->highbit)
+#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+#define ebitmap_startnode(e) ((e)->node)
+
+static inline unsigned int ebitmap_start(const ebitmap_t * e,
+ ebitmap_node_t ** n)
+{
+
+ *n = e->node;
+ return ebitmap_startbit(e);
+}
+
+static inline void ebitmap_init(ebitmap_t * e)
+{
+ memset(e, 0, sizeof(*e));
+}
+
+static inline unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit)
+{
+ if ((bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next) {
+ *n = (*n)->next;
+ return (*n)->startbit;
+ }
+
+ return (bit + 1);
+}
+
+static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit)
+{
+ if (n->map & (MAPBIT << (bit - n->startbit)))
+ return 1;
+ return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1);
+extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src);
+extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit);
+extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value);
+extern void ebitmap_destroy(ebitmap_t * e);
+extern int ebitmap_read(ebitmap_t * e, void *fp);
+
+#endif /* _EBITMAP_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/expand.h b/include/sepol/policydb/expand.h
new file mode 100644
index 0000000..31e25ec
--- /dev/null
+++ b/include/sepol/policydb/expand.h
@@ -0,0 +1,79 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_EXPAND_H
+#define _SEPOL_POLICYDB_EXPAND_H
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/conditional.h>
+
+/*
+ * Expand only the avrules for a module. It is valid for this function
+ * to expand base into itself (i.e. base == out); the typemap for
+ * this special case should map type[i] to i+1. Likewise the boolmap
+ * should map bool[i] to i + 1. This function optionally expands
+ * neverallow rules. If neverallow rules are expanded, there is no
+ * need to copy them and doing so could cause duplicate entries when
+ * base == out. If the neverallow rules are not expanded, they are
+ * just copied to the destination policy so that assertion checking
+ * can be performed after expand. No assertion or hierarchy checking
+ * is performed by this function.
+ */
+extern int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+ policydb_t * out, uint32_t * typemap, uint32_t * boolmap,
+ uint32_t * rolemap, uint32_t * usermap,
+ int verbose, int expand_neverallow);
+/*
+ * Expand all parts of a module. Neverallow rules are not expanded (only
+ * copied). It is not valid to expand base into itself. If check is non-zero,
+ * performs hierarchy and assertion checking.
+ */
+extern int expand_module(sepol_handle_t * handle,
+ policydb_t * base, policydb_t * out,
+ int verbose, int check);
+extern int convert_type_ebitmap(ebitmap_t * src, ebitmap_t * dst,
+ uint32_t * typemap);
+extern int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+ type_set_t * set, ebitmap_t * types,
+ unsigned char alwaysexpand);
+extern int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+ unsigned char alwaysexpand);
+extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap);
+extern int mls_semantic_level_expand(mls_semantic_level_t *sl, mls_level_t *l,
+ policydb_t *p, sepol_handle_t *h);
+extern int mls_semantic_range_expand(mls_semantic_range_t *sr, mls_range_t *r,
+ policydb_t *p, sepol_handle_t *h);
+extern int expand_rule(sepol_handle_t * handle,
+ policydb_t * source_pol,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other,
+ int enabled);
+
+extern int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa);
+
+extern int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+ cond_av_list_t ** newl, avtab_t * expa);
+
+#endif
diff --git a/include/sepol/policydb/flask.h b/include/sepol/policydb/flask.h
new file mode 100644
index 0000000..3134284
--- /dev/null
+++ b/include/sepol/policydb/flask.h
@@ -0,0 +1,94 @@
+/* This file is automatically generated. Do not edit. */
+#ifndef _SEPOL_POLICYDB_FLASK_H_
+#define _SEPOL_POLICYDB_FLASK_H_
+
+/*
+ * Security object class definitions
+ */
+#define SECCLASS_SECURITY 1
+#define SECCLASS_PROCESS 2
+#define SECCLASS_SYSTEM 3
+#define SECCLASS_CAPABILITY 4
+#define SECCLASS_FILESYSTEM 5
+#define SECCLASS_FILE 6
+#define SECCLASS_DIR 7
+#define SECCLASS_FD 8
+#define SECCLASS_LNK_FILE 9
+#define SECCLASS_CHR_FILE 10
+#define SECCLASS_BLK_FILE 11
+#define SECCLASS_SOCK_FILE 12
+#define SECCLASS_FIFO_FILE 13
+#define SECCLASS_SOCKET 14
+#define SECCLASS_TCP_SOCKET 15
+#define SECCLASS_UDP_SOCKET 16
+#define SECCLASS_RAWIP_SOCKET 17
+#define SECCLASS_NODE 18
+#define SECCLASS_NETIF 19
+#define SECCLASS_NETLINK_SOCKET 20
+#define SECCLASS_PACKET_SOCKET 21
+#define SECCLASS_KEY_SOCKET 22
+#define SECCLASS_UNIX_STREAM_SOCKET 23
+#define SECCLASS_UNIX_DGRAM_SOCKET 24
+#define SECCLASS_SEM 25
+#define SECCLASS_MSG 26
+#define SECCLASS_MSGQ 27
+#define SECCLASS_SHM 28
+#define SECCLASS_IPC 29
+#define SECCLASS_PASSWD 30
+#define SECCLASS_DRAWABLE 31
+#define SECCLASS_WINDOW 32
+#define SECCLASS_GC 33
+#define SECCLASS_FONT 34
+#define SECCLASS_COLORMAP 35
+#define SECCLASS_PROPERTY 36
+#define SECCLASS_CURSOR 37
+#define SECCLASS_XCLIENT 38
+#define SECCLASS_XINPUT 39
+#define SECCLASS_XSERVER 40
+#define SECCLASS_XEXTENSION 41
+#define SECCLASS_PAX 42
+#define SECCLASS_NETLINK_ROUTE_SOCKET 43
+#define SECCLASS_NETLINK_FIREWALL_SOCKET 44
+#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45
+#define SECCLASS_NETLINK_NFLOG_SOCKET 46
+#define SECCLASS_NETLINK_XFRM_SOCKET 47
+#define SECCLASS_NETLINK_SELINUX_SOCKET 48
+#define SECCLASS_NETLINK_AUDIT_SOCKET 49
+#define SECCLASS_NETLINK_IP6FW_SOCKET 50
+#define SECCLASS_NETLINK_DNRT_SOCKET 51
+#define SECCLASS_DBUS 52
+
+/*
+ * Security identifier indices for initial entities
+ */
+#define SECINITSID_KERNEL 1
+#define SECINITSID_SECURITY 2
+#define SECINITSID_UNLABELED 3
+#define SECINITSID_FS 4
+#define SECINITSID_FILE 5
+#define SECINITSID_FILE_LABELS 6
+#define SECINITSID_INIT 7
+#define SECINITSID_ANY_SOCKET 8
+#define SECINITSID_PORT 9
+#define SECINITSID_NETIF 10
+#define SECINITSID_NETMSG 11
+#define SECINITSID_NODE 12
+#define SECINITSID_IGMP_PACKET 13
+#define SECINITSID_ICMP_SOCKET 14
+#define SECINITSID_TCP_SOCKET 15
+#define SECINITSID_SYSCTL_MODPROBE 16
+#define SECINITSID_SYSCTL 17
+#define SECINITSID_SYSCTL_FS 18
+#define SECINITSID_SYSCTL_KERNEL 19
+#define SECINITSID_SYSCTL_NET 20
+#define SECINITSID_SYSCTL_NET_UNIX 21
+#define SECINITSID_SYSCTL_VM 22
+#define SECINITSID_SYSCTL_DEV 23
+#define SECINITSID_KMOD 24
+#define SECINITSID_POLICY 25
+#define SECINITSID_SCMP_PACKET 26
+#define SECINITSID_DEVNULL 27
+
+#define SECINITSID_NUM 27
+
+#endif
diff --git a/include/sepol/policydb/flask_types.h b/include/sepol/policydb/flask_types.h
new file mode 100644
index 0000000..575c6f2
--- /dev/null
+++ b/include/sepol/policydb/flask_types.h
@@ -0,0 +1,62 @@
+
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+#ifndef _SEPOL_POLICYDB_FLASK_TYPES_H_
+#define _SEPOL_POLICYDB_FLASK_TYPES_H_
+
+/*
+ * The basic Flask types and constants.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy. The security context type
+ * is defined as a variable-length string that can be
+ * interpreted by any application or user with an
+ * understanding of the security policy.
+ */
+typedef char *sepol_security_context_t;
+
+/*
+ * An access vector (AV) is a collection of related permissions
+ * for a pair of SIDs. The bits within an access vector
+ * are interpreted differently depending on the class of
+ * the object. The access vector interpretations are specified
+ * in flask/access_vectors, and the corresponding constants
+ * for permissions are defined in the automatically generated
+ * header file av_permissions.h.
+ */
+typedef uint32_t sepol_access_vector_t;
+
+/*
+ * Each object class is identified by a fixed-size value.
+ * The set of security classes is specified in flask/security_classes,
+ * with the corresponding constants defined in the automatically
+ * generated header file flask.h.
+ */
+typedef uint16_t sepol_security_class_t;
+#define SEPOL_SECCLASS_NULL 0x0000 /* no class */
+
+#define SELINUX_MAGIC 0xf97cff8c
+#define SELINUX_MOD_MAGIC 0xf97cff8d
+
+typedef uint32_t sepol_security_id_t;
+#define SEPOL_SECSID_NULL 0
+
+struct sepol_av_decision {
+ sepol_access_vector_t allowed;
+ sepol_access_vector_t decided;
+ sepol_access_vector_t auditallow;
+ sepol_access_vector_t auditdeny;
+ uint32_t seqno;
+};
+
+#endif
diff --git a/include/sepol/policydb/hashtab.h b/include/sepol/policydb/hashtab.h
new file mode 100644
index 0000000..1081ff6
--- /dev/null
+++ b/include/sepol/policydb/hashtab.h
@@ -0,0 +1,137 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A hash table (hashtab) maintains associations between
+ * key values and datum values. The type of the key values
+ * and the type of the datum values is arbitrary. The
+ * functions for hash computation and key comparison are
+ * provided by the creator of the table.
+ */
+
+#ifndef _SEPOL_POLICYDB_HASHTAB_H_
+#define _SEPOL_POLICYDB_HASHTAB_H_
+
+#include <sepol/errcodes.h>
+
+#include <stdint.h>
+#include <stdio.h>
+
+typedef char *hashtab_key_t; /* generic key type */
+typedef void *hashtab_datum_t; /* generic datum type */
+
+typedef struct hashtab_node *hashtab_ptr_t;
+
+typedef struct hashtab_node {
+ hashtab_key_t key;
+ hashtab_datum_t datum;
+ hashtab_ptr_t next;
+} hashtab_node_t;
+
+typedef struct hashtab_val {
+ hashtab_ptr_t *htable; /* hash table */
+ unsigned int size; /* number of slots in hash table */
+ uint32_t nel; /* number of elements in hash table */
+ unsigned int (*hash_value) (struct hashtab_val * h, hashtab_key_t key); /* hash function */
+ int (*keycmp) (struct hashtab_val * h, hashtab_key_t key1, hashtab_key_t key2); /* key comparison function */
+} hashtab_val_t;
+
+typedef hashtab_val_t *hashtab_t;
+
+/*
+ Creates a new hash table with the specified characteristics.
+
+ Returns NULL if insufficent space is available or
+ the new hash table otherwise.
+ */
+extern hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+ const hashtab_key_t
+ key),
+ int (*keycmp) (hashtab_t h,
+ const hashtab_key_t key1,
+ const hashtab_key_t key2),
+ unsigned int size);
+/*
+ Inserts the specified (key, datum) pair into the specified hash table.
+
+ Returns SEPOL_ENOMEM if insufficient space is available or
+ SEPOL_EEXIST if there is already an entry with the same key or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_insert(hashtab_t h, hashtab_key_t k, hashtab_datum_t d);
+
+/*
+ Removes the entry with the specified key from the hash table.
+ Applies the specified destroy function to (key,datum,args) for
+ the entry.
+
+ Returns SEPOL_ENOENT if no entry has the specified key or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_remove(hashtab_t h, hashtab_key_t k,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Insert or replace the specified (key, datum) pair in the specified
+ hash table. If an entry for the specified key already exists,
+ then the specified destroy function is applied to (key,datum,args)
+ for the entry prior to replacing the entry's contents.
+
+ Returns SEPOL_ENOMEM if insufficient space is available or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_replace(hashtab_t h, hashtab_key_t k, hashtab_datum_t d,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Searches for the entry with the specified key in the hash table.
+
+ Returns NULL if no entry has the specified key or
+ the datum of the entry otherwise.
+ */
+extern hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t k);
+
+/*
+ Destroys the specified hash table.
+ */
+extern void hashtab_destroy(hashtab_t h);
+
+/*
+ Applies the specified apply function to (key,datum,args)
+ for each entry in the specified hash table.
+
+ The order in which the function is applied to the entries
+ is dependent upon the internal structure of the hash table.
+
+ If apply returns a non-zero status, then hashtab_map will cease
+ iterating through the hash table and will propagate the error
+ return to its caller.
+ */
+extern int hashtab_map(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Same as hashtab_map, except that if apply returns a non-zero status,
+ then the (key,datum) pair will be removed from the hashtab and the
+ destroy function will be applied to (key,datum,args).
+ */
+extern void hashtab_map_remove_on_error(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void *args);
+
+extern void hashtab_hash_eval(hashtab_t h, char *tag);
+
+#endif
diff --git a/include/sepol/policydb/hierarchy.h b/include/sepol/policydb/hierarchy.h
new file mode 100644
index 0000000..de2dfc7
--- /dev/null
+++ b/include/sepol/policydb/hierarchy.h
@@ -0,0 +1,32 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_HIERARCHY_H_
+#define _SEPOL_POLICYDB_HIERARCHY_H_
+
+#include <sepol/policydb/policydb.h>
+
+extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p);
+
+#endif
diff --git a/include/sepol/policydb/link.h b/include/sepol/policydb/link.h
new file mode 100644
index 0000000..fca9114
--- /dev/null
+++ b/include/sepol/policydb/link.h
@@ -0,0 +1,20 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@mentalrootkit.com>
+ */
+
+#ifndef _SEPOL_POLICYDB_LINK_H
+#define _SEPOL_POLICYDB_LINK_H
+
+#include <sepol/handle.h>
+#include <sepol/errcodes.h>
+#include <sepol/policydb/policydb.h>
+
+
+#include <stddef.h>
+
+extern int link_modules(sepol_handle_t * handle,
+ policydb_t * b, policydb_t ** mods, int len,
+ int verbose);
+
+#endif
diff --git a/include/sepol/policydb/mls_types.h b/include/sepol/policydb/mls_types.h
new file mode 100644
index 0000000..e491209
--- /dev/null
+++ b/include/sepol/policydb/mls_types.h
@@ -0,0 +1,153 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_MLS_TYPES_H_
+#define _SEPOL_POLICYDB_MLS_TYPES_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+
+typedef struct mls_level {
+ uint32_t sens; /* sensitivity */
+ ebitmap_t cat; /* category set */
+} mls_level_t;
+
+typedef struct mls_range {
+ mls_level_t level[2]; /* low == level[0], high == level[1] */
+} mls_range_t;
+
+static inline int mls_level_cpy(struct mls_level *dst, struct mls_level *src)
+{
+
+ dst->sens = src->sens;
+ if (ebitmap_cpy(&dst->cat, &src->cat) < 0)
+ return -1;
+ return 0;
+}
+
+static inline void mls_level_init(struct mls_level *level)
+{
+
+ memset(level, 0, sizeof(mls_level_t));
+}
+
+static inline void mls_level_destroy(struct mls_level *level)
+{
+
+ if (level == NULL)
+ return;
+
+ ebitmap_destroy(&level->cat);
+ mls_level_init(level);
+}
+
+static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2)
+{
+ return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2)
+{
+ return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
+
+static inline int mls_range_cpy(mls_range_t * dst, mls_range_t * src)
+{
+
+ if (mls_level_cpy(&dst->level[0], &src->level[0]) < 0)
+ goto err;
+
+ if (mls_level_cpy(&dst->level[1], &src->level[1]) < 0)
+ goto err_destroy;
+
+ return 0;
+
+ err_destroy:
+ mls_level_destroy(&dst->level[0]);
+
+ err:
+ return -1;
+}
+
+static inline void mls_range_init(struct mls_range *r)
+{
+ mls_level_init(&r->level[0]);
+ mls_level_init(&r->level[1]);
+}
+
+static inline void mls_range_destroy(struct mls_range *r)
+{
+ mls_level_destroy(&r->level[0]);
+ mls_level_destroy(&r->level[1]);
+}
+
+static inline int mls_range_eq(struct mls_range *r1, struct mls_range *r2)
+{
+ return (mls_level_eq(&r1->level[0], &r2->level[0]) &&
+ mls_level_eq(&r1->level[1], &r2->level[1]));
+}
+
+typedef struct mls_semantic_cat {
+ uint32_t low; /* first bit this struct represents */
+ uint32_t high; /* last bit represented - equals low for a single cat */
+ struct mls_semantic_cat *next;
+} mls_semantic_cat_t;
+
+typedef struct mls_semantic_level {
+ uint32_t sens;
+ mls_semantic_cat_t *cat;
+} mls_semantic_level_t;
+
+typedef struct mls_semantic_range {
+ mls_semantic_level_t level[2];
+} mls_semantic_range_t;
+
+extern void mls_semantic_cat_init(mls_semantic_cat_t *c);
+extern void mls_semantic_cat_destroy(mls_semantic_cat_t *c);
+extern void mls_semantic_level_init(mls_semantic_level_t *l);
+extern void mls_semantic_level_destroy(mls_semantic_level_t *l);
+extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, mls_semantic_level_t *src);
+extern void mls_semantic_range_init(mls_semantic_range_t *r);
+extern void mls_semantic_range_destroy(mls_semantic_range_t *r);
+extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, mls_semantic_range_t *src);
+
+#endif
diff --git a/include/sepol/policydb/module.h b/include/sepol/policydb/module.h
new file mode 100644
index 0000000..10403c8
--- /dev/null
+++ b/include/sepol/policydb/module.h
@@ -0,0 +1,48 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_MODULE_H_
+#define _SEPOL_POLICYDB_MODULE_H_
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <sepol/module.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#define SEPOL_MODULE_PACKAGE_MAGIC 0xf97cff8f
+
+struct sepol_module_package {
+ sepol_policydb_t *policy;
+ uint32_t version;
+ char *file_contexts;
+ size_t file_contexts_len;
+ char *seusers;
+ size_t seusers_len;
+ char *user_extra;
+ size_t user_extra_len;
+ char *netfilter_contexts;
+ size_t netfilter_contexts_len;
+};
+
+extern int sepol_module_package_init(sepol_module_package_t * p);
+
+#endif
diff --git a/include/sepol/policydb/polcaps.h b/include/sepol/policydb/polcaps.h
new file mode 100644
index 0000000..40c0a48
--- /dev/null
+++ b/include/sepol/policydb/polcaps.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_POLICYDB_POLCAPS_H_
+#define _SEPOL_POLICYDB_POLCAPS_H_
+
+/* Policy capabilities */
+enum {
+ POLICYDB_CAPABILITY_NETPEER,
+ POLICYDB_CAPABILITY_OPENPERM,
+ __POLICYDB_CAPABILITY_MAX
+};
+#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+
+/* Convert a capability name to number. */
+extern int sepol_polcap_getnum(const char *name);
+
+/* Convert a capability number to name. */
+extern const char *sepol_polcap_getname(int capnum);
+
+#endif /* _SEPOL_POLICYDB_POLCAPS_H_ */
diff --git a/include/sepol/policydb/policydb.h b/include/sepol/policydb/policydb.h
new file mode 100644
index 0000000..5320bc8
--- /dev/null
+++ b/include/sepol/policydb/policydb.h
@@ -0,0 +1,724 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Module support
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * A policy database (policydb) specifies the
+ * configuration data for the security policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_POLICYDB_H_
+#define _SEPOL_POLICYDB_POLICYDB_H_
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include <sepol/policydb.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/sidtab.h>
+
+#define ERRMSG_LEN 1024
+
+#define POLICYDB_SUCCESS 0
+#define POLICYDB_ERROR -1
+#define POLICYDB_UNSUPPORTED -2
+
+/*
+ * A datum type is defined for each kind of symbol
+ * in the configuration data: individual permissions,
+ * common prefixes for access vectors, classes,
+ * users, roles, types, sensitivities, categories, etc.
+ */
+
+/* type set preserves data needed by modules such as *, ~ and attributes */
+typedef struct type_set {
+ ebitmap_t types;
+ ebitmap_t negset;
+#define TYPE_STAR 1
+#define TYPE_COMP 2
+ uint32_t flags;
+} type_set_t;
+
+typedef struct role_set {
+ ebitmap_t roles;
+#define ROLE_STAR 1
+#define ROLE_COMP 2
+ uint32_t flags;
+} role_set_t;
+
+/* Permission attributes */
+typedef struct perm_datum {
+ symtab_datum_t s;
+} perm_datum_t;
+
+/* Attributes of a common prefix for access vectors */
+typedef struct common_datum {
+ symtab_datum_t s;
+ symtab_t permissions; /* common permissions */
+} common_datum_t;
+
+/* Class attributes */
+typedef struct class_datum {
+ symtab_datum_t s;
+ char *comkey; /* common name */
+ common_datum_t *comdatum; /* common datum */
+ symtab_t permissions; /* class-specific permission symbol table */
+ constraint_node_t *constraints; /* constraints on class permissions */
+ constraint_node_t *validatetrans; /* special transition rules */
+} class_datum_t;
+
+/* Role attributes */
+typedef struct role_datum {
+ symtab_datum_t s;
+ ebitmap_t dominates; /* set of roles dominated by this role */
+ type_set_t types; /* set of authorized types for role */
+ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */
+ uint32_t bounds; /* bounds role, if exist */
+#define ROLE_ROLE 0 /* regular role in kernel policies */
+#define ROLE_ATTRIB 1 /* attribute */
+ uint32_t flavor;
+ ebitmap_t roles; /* roles with this attribute */
+} role_datum_t;
+
+typedef struct role_trans {
+ uint32_t role; /* current role */
+ uint32_t type; /* program executable type, or new object type */
+ uint32_t tclass; /* process class, or new object class */
+ uint32_t new_role; /* new role */
+ struct role_trans *next;
+} role_trans_t;
+
+typedef struct role_allow {
+ uint32_t role; /* current role */
+ uint32_t new_role; /* new role */
+ struct role_allow *next;
+} role_allow_t;
+
+/* filename_trans rules */
+typedef struct filename_trans {
+ uint32_t stype;
+ uint32_t ttype;
+ uint32_t tclass;
+ char *name;
+ uint32_t otype;
+ struct filename_trans *next;
+} filename_trans_t;
+
+/* Type attributes */
+typedef struct type_datum {
+ symtab_datum_t s;
+ uint32_t primary; /* primary name? can be set to primary value if below is TYPE_ */
+#define TYPE_TYPE 0 /* regular type or alias in kernel policies */
+#define TYPE_ATTRIB 1 /* attribute */
+#define TYPE_ALIAS 2 /* alias in modular policy */
+ uint32_t flavor;
+ ebitmap_t types; /* types with this attribute */
+#define TYPE_FLAGS_PERMISSIVE 0x01
+ uint32_t flags;
+ uint32_t bounds; /* bounds type, if exist */
+} type_datum_t;
+
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY 0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002
+#define TYPEDATUM_PROPERTY_ALIAS 0x0004 /* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE 0x0008 /* userspace only */
+
+/* User attributes */
+typedef struct user_datum {
+ symtab_datum_t s;
+ role_set_t roles; /* set of authorized roles for user */
+ mls_semantic_range_t range; /* MLS range (min. - max.) for user */
+ mls_semantic_level_t dfltlevel; /* default login MLS level for user */
+ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */
+ mls_range_t exp_range; /* expanded range used for validation */
+ mls_level_t exp_dfltlevel; /* expanded range used for validation */
+ uint32_t bounds; /* bounds user, if exist */
+} user_datum_t;
+
+/* Sensitivity attributes */
+typedef struct level_datum {
+ mls_level_t *level; /* sensitivity and associated categories */
+ unsigned char isalias; /* is this sensitivity an alias for another? */
+ unsigned char defined;
+} level_datum_t;
+
+/* Category attributes */
+typedef struct cat_datum {
+ symtab_datum_t s;
+ unsigned char isalias; /* is this category an alias for another? */
+} cat_datum_t;
+
+typedef struct range_trans {
+ uint32_t source_type;
+ uint32_t target_type;
+ uint32_t target_class;
+ mls_range_t target_range;
+ struct range_trans *next;
+} range_trans_t;
+
+/* Boolean data type */
+typedef struct cond_bool_datum {
+ symtab_datum_t s;
+ int state;
+} cond_bool_datum_t;
+
+struct cond_node;
+
+typedef struct cond_node cond_list_t;
+struct cond_av_list;
+
+typedef struct class_perm_node {
+ uint32_t class;
+ uint32_t data; /* permissions or new type */
+ struct class_perm_node *next;
+} class_perm_node_t;
+
+typedef struct avrule {
+/* these typedefs are almost exactly the same as those in avtab.h - they are
+ * here because of the need to include neverallow and dontaudit messages */
+#define AVRULE_ALLOWED 1
+#define AVRULE_AUDITALLOW 2
+#define AVRULE_AUDITDENY 4
+#define AVRULE_DONTAUDIT 8
+#define AVRULE_NEVERALLOW 128
+#define AVRULE_AV (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define AVRULE_TRANSITION 16
+#define AVRULE_MEMBER 32
+#define AVRULE_CHANGE 64
+#define AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+ uint32_t specified;
+#define RULE_SELF 1
+ uint32_t flags;
+ type_set_t stypes;
+ type_set_t ttypes;
+ class_perm_node_t *perms;
+ unsigned long line; /* line number from policy.conf where
+ * this rule originated */
+ struct avrule *next;
+} avrule_t;
+
+typedef struct role_trans_rule {
+ role_set_t roles; /* current role */
+ type_set_t types; /* program executable type, or new object type */
+ ebitmap_t classes; /* process class, or new object class */
+ uint32_t new_role; /* new role */
+ struct role_trans_rule *next;
+} role_trans_rule_t;
+
+typedef struct role_allow_rule {
+ role_set_t roles; /* current role */
+ role_set_t new_roles; /* new roles */
+ struct role_allow_rule *next;
+} role_allow_rule_t;
+
+typedef struct filename_trans_rule {
+ type_set_t stypes;
+ type_set_t ttypes;
+ uint32_t tclass;
+ char *name;
+ uint32_t otype; /* new type */
+ struct filename_trans_rule *next;
+} filename_trans_rule_t;
+
+typedef struct range_trans_rule {
+ type_set_t stypes;
+ type_set_t ttypes;
+ ebitmap_t tclasses;
+ mls_semantic_range_t trange;
+ struct range_trans_rule *next;
+} range_trans_rule_t;
+
+/*
+ * The configuration data includes security contexts for
+ * initial SIDs, unlabeled file systems, TCP and UDP port numbers,
+ * network interfaces, and nodes. This structure stores the
+ * relevant data for one such entry. Entries of the same kind
+ * (e.g. all initial SIDs) are linked together into a list.
+ */
+typedef struct ocontext {
+ union {
+ char *name; /* name of initial SID, fs, netif, fstype, path */
+ struct {
+ uint8_t protocol;
+ uint16_t low_port;
+ uint16_t high_port;
+ } port; /* TCP or UDP port information */
+ struct {
+ uint32_t addr; /* network order */
+ uint32_t mask; /* network order */
+ } node; /* node information */
+ struct {
+ uint32_t addr[4]; /* network order */
+ uint32_t mask[4]; /* network order */
+ } node6; /* IPv6 node information */
+ uint32_t device;
+ uint16_t pirq;
+ struct {
+ uint32_t low_iomem;
+ uint32_t high_iomem;
+ } iomem;
+ struct {
+ uint32_t low_ioport;
+ uint32_t high_ioport;
+ } ioport;
+ } u;
+ union {
+ uint32_t sclass; /* security class for genfs */
+ uint32_t behavior; /* labeling behavior for fs_use */
+ } v;
+ context_struct_t context[2]; /* security context(s) */
+ sepol_security_id_t sid[2]; /* SID(s) */
+ struct ocontext *next;
+} ocontext_t;
+
+typedef struct genfs {
+ char *fstype;
+ struct ocontext *head;
+ struct genfs *next;
+} genfs_t;
+
+/* symbol table array indices */
+#define SYM_COMMONS 0
+#define SYM_CLASSES 1
+#define SYM_ROLES 2
+#define SYM_TYPES 3
+#define SYM_USERS 4
+#define SYM_BOOLS 5
+#define SYM_LEVELS 6
+#define SYM_CATS 7
+#define SYM_NUM 8
+
+/* object context array indices */
+#define OCON_ISID 0 /* initial SIDs */
+#define OCON_FS 1 /* unlabeled file systems */
+#define OCON_PORT 2 /* TCP and UDP port numbers */
+#define OCON_NETIF 3 /* network interfaces */
+#define OCON_NODE 4 /* nodes */
+#define OCON_FSUSE 5 /* fs_use */
+#define OCON_NODE6 6 /* IPv6 nodes */
+#define OCON_GENFS 7 /* needed for ocontext_supported */
+
+/* object context array indices for Xen */
+#define OCON_XEN_ISID 0 /* initial SIDs */
+#define OCON_XEN_PIRQ 1 /* physical irqs */
+#define OCON_XEN_IOPORT 2 /* io ports */
+#define OCON_XEN_IOMEM 3 /* io memory */
+#define OCON_XEN_PCIDEVICE 4 /* pci devices */
+
+/* OCON_NUM needs to be the largest index in any platform's ocontext array */
+#define OCON_NUM 7
+
+/* section: module information */
+
+/* scope_index_t holds all of the symbols that are in scope in a
+ * particular situation. The bitmaps are indices (and thus must
+ * subtract one) into the global policydb->scope array. */
+typedef struct scope_index {
+ ebitmap_t scope[SYM_NUM];
+#define p_classes_scope scope[SYM_CLASSES]
+#define p_roles_scope scope[SYM_ROLES]
+#define p_types_scope scope[SYM_TYPES]
+#define p_users_scope scope[SYM_USERS]
+#define p_bools_scope scope[SYM_BOOLS]
+#define p_sens_scope scope[SYM_LEVELS]
+#define p_cat_scope scope[SYM_CATS]
+
+ /* this array maps from class->value to the permissions within
+ * scope. if bit (perm->value - 1) is set in map
+ * class_perms_map[class->value - 1] then that permission is
+ * enabled for this class within this decl. */
+ ebitmap_t *class_perms_map;
+ /* total number of classes in class_perms_map array */
+ uint32_t class_perms_len;
+} scope_index_t;
+
+/* a list of declarations for a particular avrule_decl */
+
+/* These two structs declare a block of policy that has TE and RBAC
+ * statements and declarations. The root block (the global policy)
+ * can never have an ELSE branch. */
+typedef struct avrule_decl {
+ uint32_t decl_id;
+ uint32_t enabled; /* whether this block is enabled */
+
+ cond_list_t *cond_list;
+ avrule_t *avrules;
+ role_trans_rule_t *role_tr_rules;
+ role_allow_rule_t *role_allow_rules;
+ range_trans_rule_t *range_tr_rules;
+ scope_index_t required; /* symbols needed to activate this block */
+ scope_index_t declared; /* symbols declared within this block */
+
+ /* type transition rules with a 'name' component */
+ filename_trans_rule_t *filename_trans_rules;
+
+ /* for additive statements (type attribute, roles, and users) */
+ symtab_t symtab[SYM_NUM];
+
+ /* In a linked module this will contain the name of the module
+ * from which this avrule_decl originated. */
+ char *module_name;
+
+ struct avrule_decl *next;
+} avrule_decl_t;
+
+typedef struct avrule_block {
+ avrule_decl_t *branch_list;
+ avrule_decl_t *enabled; /* pointer to which branch is enabled. this is
+ used in linking and never written to disk */
+#define AVRULE_OPTIONAL 1
+ uint32_t flags; /* any flags for this block, currently just optional */
+ struct avrule_block *next;
+} avrule_block_t;
+
+/* Every identifier has its own scope datum. The datum describes if
+ * the item is to be included into the final policy during
+ * expansion. */
+typedef struct scope_datum {
+/* Required for this decl */
+#define SCOPE_REQ 1
+/* Declared in this decl */
+#define SCOPE_DECL 2
+ uint32_t scope;
+ uint32_t *decl_ids;
+ uint32_t decl_ids_len;
+ /* decl_ids is a list of avrule_decl's that declare/require
+ * this symbol. If scope==SCOPE_DECL then this is a list of
+ * declarations. If the symbol may only be declared once
+ * (types, bools) then decl_ids_len will be exactly 1. For
+ * implicitly declared things (roles, users) then decl_ids_len
+ * will be at least 1. */
+} scope_datum_t;
+
+/* The policy database */
+typedef struct policydb {
+#define POLICY_KERN SEPOL_POLICY_KERN
+#define POLICY_BASE SEPOL_POLICY_BASE
+#define POLICY_MOD SEPOL_POLICY_MOD
+ uint32_t policy_type;
+ char *name;
+ char *version;
+ int target_platform;
+
+ /* Set when the policydb is modified such that writing is unsupported */
+ int unsupported_format;
+
+ /* Whether this policydb is mls, should always be set */
+ int mls;
+
+ /* symbol tables */
+ symtab_t symtab[SYM_NUM];
+#define p_commons symtab[SYM_COMMONS]
+#define p_classes symtab[SYM_CLASSES]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
+
+ /* symbol names indexed by (value - 1) */
+ char **sym_val_to_name[SYM_NUM];
+#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
+#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
+#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
+#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
+#define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
+#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
+#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+
+ /* class, role, and user attributes indexed by (value - 1) */
+ class_datum_t **class_val_to_struct;
+ role_datum_t **role_val_to_struct;
+ user_datum_t **user_val_to_struct;
+ type_datum_t **type_val_to_struct;
+
+ /* module stuff section -- used in parsing and for modules */
+
+ /* keep track of the scope for every identifier. these are
+ * hash tables, where the key is the identifier name and value
+ * a scope_datum_t. as a convenience, one may use the
+ * p_*_macros (cf. struct scope_index_t declaration). */
+ symtab_t scope[SYM_NUM];
+
+ /* module rule storage */
+ avrule_block_t *global;
+ /* avrule_decl index used for link/expand */
+ avrule_decl_t **decl_val_to_struct;
+
+ /* compiled storage of rules - use for the kernel policy */
+
+ /* type enforcement access vectors and transitions */
+ avtab_t te_avtab;
+
+ /* bools indexed by (value - 1) */
+ cond_bool_datum_t **bool_val_to_struct;
+ /* type enforcement conditional access vectors and transitions */
+ avtab_t te_cond_avtab;
+ /* linked list indexing te_cond_avtab by conditional */
+ cond_list_t *cond_list;
+
+ /* role transitions */
+ role_trans_t *role_tr;
+
+ /* type transition rules with a 'name' component */
+ filename_trans_t *filename_trans;
+
+ /* role allows */
+ role_allow_t *role_allow;
+
+ /* security contexts of initial SIDs, unlabeled file systems,
+ TCP or UDP port numbers, network interfaces and nodes */
+ ocontext_t *ocontexts[OCON_NUM];
+
+ /* security contexts for files in filesystems that cannot support
+ a persistent label mapping or use another
+ fixed labeling behavior. */
+ genfs_t *genfs;
+
+ /* range transitions */
+ range_trans_t *range_tr;
+
+ ebitmap_t *type_attr_map;
+
+ ebitmap_t *attr_type_map; /* not saved in the binary policy */
+
+ ebitmap_t policycaps;
+
+ /* this bitmap is referenced by type NOT the typical type-1 used in other
+ bitmaps. Someday the 0 bit may be used for global permissive */
+ ebitmap_t permissive_map;
+
+ unsigned policyvers;
+
+ unsigned handle_unknown;
+} policydb_t;
+
+struct sepol_policydb {
+ struct policydb p;
+};
+
+extern int policydb_init(policydb_t * p);
+
+extern int policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, policydb_t * policydb);
+
+extern int policydb_to_image(sepol_handle_t * handle,
+ policydb_t * policydb, void **newdata,
+ size_t * newlen);
+
+extern int policydb_index_classes(policydb_t * p);
+
+extern int policydb_index_bools(policydb_t * p);
+
+extern int policydb_index_others(sepol_handle_t * handle, policydb_t * p,
+ unsigned int verbose);
+
+extern int policydb_reindex_users(policydb_t * p);
+
+extern void policydb_destroy(policydb_t * p);
+
+extern int policydb_load_isids(policydb_t * p, sidtab_t * s);
+
+/* Deprecated */
+extern int policydb_context_isvalid(const policydb_t * p,
+ const context_struct_t * c);
+
+extern void symtabs_destroy(symtab_t * symtab);
+extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
+typedef void (*hashtab_destroy_func_t) (hashtab_key_t k, hashtab_datum_t d,
+ void *args);
+extern hashtab_destroy_func_t get_symtab_destroy_func(int sym_num);
+
+extern void class_perm_node_init(class_perm_node_t * x);
+extern void type_set_init(type_set_t * x);
+extern void type_set_destroy(type_set_t * x);
+extern int type_set_cpy(type_set_t * dst, type_set_t * src);
+extern int type_set_or_eq(type_set_t * dst, type_set_t * other);
+extern void role_set_init(role_set_t * x);
+extern void role_set_destroy(role_set_t * x);
+extern void avrule_init(avrule_t * x);
+extern void avrule_destroy(avrule_t * x);
+extern void avrule_list_destroy(avrule_t * x);
+extern void role_trans_rule_init(role_trans_rule_t * x);
+extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
+extern void filename_trans_rule_init(filename_trans_rule_t * x);
+extern void filename_trans_rule_list_destroy(filename_trans_rule_t * x);
+
+extern void role_datum_init(role_datum_t * x);
+extern void role_datum_destroy(role_datum_t * x);
+extern void role_allow_rule_init(role_allow_rule_t * x);
+extern void role_allow_rule_destroy(role_allow_rule_t * x);
+extern void role_allow_rule_list_destroy(role_allow_rule_t * x);
+extern void range_trans_rule_init(range_trans_rule_t *x);
+extern void range_trans_rule_destroy(range_trans_rule_t *x);
+extern void range_trans_rule_list_destroy(range_trans_rule_t *x);
+extern void type_datum_init(type_datum_t * x);
+extern void type_datum_destroy(type_datum_t * x);
+extern void user_datum_init(user_datum_t * x);
+extern void user_datum_destroy(user_datum_t * x);
+extern void level_datum_init(level_datum_t * x);
+extern void level_datum_destroy(level_datum_t * x);
+extern void cat_datum_init(cat_datum_t * x);
+extern void cat_datum_destroy(cat_datum_t * x);
+
+extern int check_assertions(sepol_handle_t * handle,
+ policydb_t * p, avrule_t * avrules);
+
+extern int symtab_insert(policydb_t * x, uint32_t sym,
+ hashtab_key_t key, hashtab_datum_t datum,
+ uint32_t scope, uint32_t avrule_decl_id,
+ uint32_t * value);
+
+/* A policy "file" may be a memory region referenced by a (data, len) pair
+ or a file referenced by a FILE pointer. */
+typedef struct policy_file {
+#define PF_USE_MEMORY 0
+#define PF_USE_STDIO 1
+#define PF_LEN 2 /* total up length in len field */
+ unsigned type;
+ char *data;
+ size_t len;
+ size_t size;
+ FILE *fp;
+ struct sepol_handle *handle;
+} policy_file_t;
+
+struct sepol_policy_file {
+ struct policy_file pf;
+};
+
+extern void policy_file_init(policy_file_t * x);
+
+extern int policydb_read(policydb_t * p, struct policy_file *fp,
+ unsigned int verbose);
+extern int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+ struct policy_file *fp);
+
+extern int policydb_write(struct policydb *p, struct policy_file *pf);
+extern int policydb_set_target_platform(policydb_t *p, int platform);
+
+#define PERM_SYMTAB_SIZE 32
+
+/* Identify specific policy version changes */
+#define POLICYDB_VERSION_BASE 15
+#define POLICYDB_VERSION_BOOL 16
+#define POLICYDB_VERSION_IPV6 17
+#define POLICYDB_VERSION_NLCLASS 18
+#define POLICYDB_VERSION_VALIDATETRANS 19
+#define POLICYDB_VERSION_MLS 19
+#define POLICYDB_VERSION_AVTAB 20
+#define POLICYDB_VERSION_RANGETRANS 21
+#define POLICYDB_VERSION_POLCAP 22
+#define POLICYDB_VERSION_PERMISSIVE 23
+#define POLICYDB_VERSION_BOUNDARY 24
+#define POLICYDB_VERSION_FILENAME_TRANS 25
+#define POLICYDB_VERSION_ROLETRANS 26
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS
+
+/* Module versions and specific changes*/
+#define MOD_POLICYDB_VERSION_BASE 4
+#define MOD_POLICYDB_VERSION_VALIDATETRANS 5
+#define MOD_POLICYDB_VERSION_MLS 5
+#define MOD_POLICYDB_VERSION_RANGETRANS 6
+#define MOD_POLICYDB_VERSION_MLS_USERS 6
+#define MOD_POLICYDB_VERSION_POLCAP 7
+#define MOD_POLICYDB_VERSION_PERMISSIVE 8
+#define MOD_POLICYDB_VERSION_BOUNDARY 9
+#define MOD_POLICYDB_VERSION_BOUNDARY_ALIAS 10
+#define MOD_POLICYDB_VERSION_FILENAME_TRANS 11
+#define MOD_POLICYDB_VERSION_ROLETRANS 12
+#define MOD_POLICYDB_VERSION_ROLEATTRIB 13
+
+#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_ROLEATTRIB
+
+#define POLICYDB_CONFIG_MLS 1
+
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p) \
+ (((p)->policy_type == POLICY_KERN \
+ && p->policyvers >= POLICYDB_VERSION_BOUNDARY) || \
+ ((p)->policy_type != POLICY_KERN \
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
+/* the config flags related to unknown classes/perms are bits 2 and 3 */
+#define DENY_UNKNOWN SEPOL_DENY_UNKNOWN
+#define REJECT_UNKNOWN SEPOL_REJECT_UNKNOWN
+#define ALLOW_UNKNOWN SEPOL_ALLOW_UNKNOWN
+
+#define POLICYDB_CONFIG_UNKNOWN_MASK (DENY_UNKNOWN | REJECT_UNKNOWN | ALLOW_UNKNOWN)
+
+#define OBJECT_R "object_r"
+#define OBJECT_R_VAL 1
+
+#define POLICYDB_MAGIC SELINUX_MAGIC
+#define POLICYDB_STRING "SE Linux"
+#define POLICYDB_XEN_STRING "XenFlask"
+#define POLICYDB_STRING_MAX_LENGTH 32
+#define POLICYDB_MOD_MAGIC SELINUX_MOD_MAGIC
+#define POLICYDB_MOD_STRING "SE Linux Module"
+#define SEPOL_TARGET_SELINUX 0
+#define SEPOL_TARGET_XEN 1
+
+
+#endif /* _POLICYDB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/services.h b/include/sepol/policydb/services.h
new file mode 100644
index 0000000..aef0c7b
--- /dev/null
+++ b/include/sepol/policydb/services.h
@@ -0,0 +1,184 @@
+
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+#ifndef _SEPOL_POLICYDB_SERVICES_H_
+#define _SEPOL_POLICYDB_SERVICES_H_
+
+/*
+ * Security server interface.
+ */
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <stddef.h>
+
+/* Set the policydb and sidtab structures to be used by
+ the service functions. If not set, then these default
+ to private structures within libsepol that can only be
+ initialized and accessed via the service functions themselves.
+ Setting the structures explicitly allows a program to directly
+ manipulate them, e.g. checkpolicy populates the structures directly
+ from a source policy rather than from a binary policy. */
+extern int sepol_set_policydb(policydb_t * p);
+extern int sepol_set_sidtab(sidtab_t * s);
+
+/* Modify a policydb for boolean settings. */
+int sepol_genbools_policydb(policydb_t * policydb, const char *booleans);
+
+/* Modify a policydb for user settings. */
+int sepol_genusers_policydb(policydb_t * policydb, const char *usersdir);
+
+/* Load the security policy. This initializes the policydb
+ and sidtab based on the provided binary policy. */
+extern int sepol_load_policy(void *data, size_t len);
+
+/*
+ * Compute access vectors based on a SID pair for
+ * the permissions in a particular class.
+ */
+extern int sepol_compute_av(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_access_vector_t requested, /* IN */
+ struct sepol_av_decision *avd); /* OUT */
+
+/* Same as above, but also return the reason(s) for any
+ denials of the requested permissions. */
+#define SEPOL_COMPUTEAV_TE 1
+#define SEPOL_COMPUTEAV_CONS 2
+#define SEPOL_COMPUTEAV_RBAC 4
+extern int sepol_compute_av_reason(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason);
+
+/*
+ * Compute a SID to use for labeling a new object in the
+ * class `tclass' based on a SID pair.
+ */
+extern int sepol_transition_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Compute a SID to use when selecting a member of a
+ * polyinstantiated object of class `tclass' based on
+ * a SID pair.
+ */
+extern int sepol_member_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Compute a SID to use for relabeling an object in the
+ * class `tclass' based on a SID pair.
+ */
+extern int sepol_change_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Write the security context string representation of
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+extern int sepol_sid_to_context(sepol_security_id_t sid, /* IN */
+ sepol_security_context_t * scontext, /* OUT */
+ size_t * scontext_len); /* OUT */
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+extern int sepol_context_to_sid(const sepol_security_context_t scontext, /* IN */
+ size_t scontext_len, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated
+ * array containing the set of SIDs. Set `*nel' to the
+ * number of elements in the array.
+ */
+extern int sepol_get_user_sids(sepol_security_id_t callsid,
+ char *username,
+ sepol_security_id_t ** sids, uint32_t * nel);
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'. The `fs_sid' SID is returned for
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+extern int sepol_fs_sid(char *dev, /* IN */
+ sepol_security_id_t * fs_sid, /* OUT */
+ sepol_security_id_t * file_sid); /* OUT */
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+extern int sepol_port_sid(uint16_t domain,
+ uint16_t type,
+ uint8_t protocol,
+ uint16_t port, sepol_security_id_t * out_sid);
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'. The `if_sid' SID is returned for
+ * the interface and the `msg_sid' SID is returned as
+ * the default SID for messages received on the
+ * interface.
+ */
+extern int sepol_netif_sid(char *name,
+ sepol_security_id_t * if_sid,
+ sepol_security_id_t * msg_sid);
+
+/*
+ * Return the SID of the node specified by the address
+ * `addr' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+extern int sepol_node_sid(uint16_t domain,
+ void *addr,
+ size_t addrlen, sepol_security_id_t * out_sid);
+
+/*
+ * Return a value indicating how to handle labeling for the
+ * the specified filesystem type, and optionally return a SID
+ * for the filesystem object.
+ */
+#define SECURITY_FS_USE_XATTR 1 /* use xattr */
+#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
+#define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */
+#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
+#define SECURITY_FS_USE_NONE 5 /* no labeling support */
+extern int sepol_fs_use(const char *fstype, /* IN */
+ unsigned int *behavior, /* OUT */
+ sepol_security_id_t * sid); /* OUT */
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+extern int sepol_genfs_sid(const char *fstype, /* IN */
+ char *name, /* IN */
+ sepol_security_class_t sclass, /* IN */
+ sepol_security_id_t * sid); /* OUT */
+
+#endif
diff --git a/include/sepol/policydb/sidtab.h b/include/sepol/policydb/sidtab.h
new file mode 100644
index 0000000..33c7cb5
--- /dev/null
+++ b/include/sepol/policydb/sidtab.h
@@ -0,0 +1,72 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ */
+
+#ifndef _SEPOL_POLICYDB_SIDTAB_H_
+#define _SEPOL_POLICYDB_SIDTAB_H_
+
+#include <sepol/policydb/context.h>
+
+typedef struct sidtab_node {
+ sepol_security_id_t sid; /* security identifier */
+ context_struct_t context; /* security context structure */
+ struct sidtab_node *next;
+} sidtab_node_t;
+
+typedef struct sidtab_node *sidtab_ptr_t;
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+typedef struct {
+ sidtab_ptr_t *htable;
+ unsigned int nel; /* number of elements */
+ unsigned int next_sid; /* next SID to allocate */
+ unsigned char shutdown;
+} sidtab_t;
+
+extern int sepol_sidtab_init(sidtab_t * s);
+
+extern int sepol_sidtab_insert(sidtab_t * s,
+ sepol_security_id_t sid,
+ context_struct_t * context);
+
+extern context_struct_t *sepol_sidtab_search(sidtab_t * s,
+ sepol_security_id_t sid);
+
+extern int sepol_sidtab_map(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args);
+
+extern void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+ int (*apply) (sepol_security_id_t
+ s,
+ context_struct_t *
+ context, void *args),
+ void *args);
+
+extern int sepol_sidtab_context_to_sid(sidtab_t * s, /* IN */
+ context_struct_t * context, /* IN */
+ sepol_security_id_t * sid); /* OUT */
+
+extern void sepol_sidtab_hash_eval(sidtab_t * h, char *tag);
+
+extern void sepol_sidtab_destroy(sidtab_t * s);
+
+extern void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src);
+
+extern void sepol_sidtab_shutdown(sidtab_t * s);
+
+#endif /* _SIDTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/symtab.h b/include/sepol/policydb/symtab.h
new file mode 100644
index 0000000..c8ad664
--- /dev/null
+++ b/include/sepol/policydb/symtab.h
@@ -0,0 +1,38 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A symbol table (symtab) maintains associations between symbol
+ * strings and datum values. The type of the datum values
+ * is arbitrary. The symbol table type is implemented
+ * using the hash table type (hashtab).
+ */
+
+#ifndef _SEPOL_POLICYDB_SYMTAB_H_
+#define _SEPOL_POLICYDB_SYMTAB_H_
+
+#include <sepol/policydb/hashtab.h>
+
+/* The symtab_datum struct stores the common information for
+ * all symtab datums. It should the first element in every
+ * struct that will be used in a symtab to allow the specific
+ * datum types to be freely cast to this type.
+ *
+ * The values start at 1 - 0 is never a valid value.
+ */
+typedef struct symtab_datum {
+ uint32_t value;
+} symtab_datum_t;
+
+typedef struct {
+ hashtab_t table; /* hash table (keyed on a string) */
+ uint32_t nprim; /* number of primary names in table */
+} symtab_t;
+
+extern int symtab_init(symtab_t *, unsigned int size);
+
+#endif /* _SYMTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/util.h b/include/sepol/policydb/util.h
new file mode 100644
index 0000000..40bfaa6
--- /dev/null
+++ b/include/sepol/policydb/util.h
@@ -0,0 +1,31 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SEPOL_UTIL_H__
+#define __SEPOL_UTIL_H__
+
+extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
+
+extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+ sepol_access_vector_t av);
+
+#endif
diff --git a/include/sepol/port_record.h b/include/sepol/port_record.h
new file mode 100644
index 0000000..b347e08
--- /dev/null
+++ b/include/sepol/port_record.h
@@ -0,0 +1,66 @@
+#ifndef _SEPOL_PORT_RECORD_H_
+#define _SEPOL_PORT_RECORD_H_
+
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+
+struct sepol_port;
+struct sepol_port_key;
+typedef struct sepol_port sepol_port_t;
+typedef struct sepol_port_key sepol_port_key_t;
+
+#define SEPOL_PROTO_UDP 0
+#define SEPOL_PROTO_TCP 1
+
+/* Key */
+extern int sepol_port_compare(const sepol_port_t * port,
+ const sepol_port_key_t * key);
+
+extern int sepol_port_compare2(const sepol_port_t * port,
+ const sepol_port_t * port2);
+
+extern int sepol_port_key_create(sepol_handle_t * handle,
+ int low, int high, int proto,
+ sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_unpack(const sepol_port_key_t * key,
+ int *low, int *high, int *proto);
+
+extern int sepol_port_key_extract(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_free(sepol_port_key_t * key);
+
+/* Protocol */
+extern int sepol_port_get_proto(const sepol_port_t * port);
+
+extern void sepol_port_set_proto(sepol_port_t * port, int proto);
+
+extern const char *sepol_port_get_proto_str(int proto);
+
+/* Port */
+extern int sepol_port_get_low(const sepol_port_t * port);
+
+extern int sepol_port_get_high(const sepol_port_t * port);
+
+extern void sepol_port_set_port(sepol_port_t * port, int port_num);
+
+extern void sepol_port_set_range(sepol_port_t * port, int low, int high);
+
+/* Context */
+extern sepol_context_t *sepol_port_get_con(const sepol_port_t * port);
+
+extern int sepol_port_set_con(sepol_handle_t * handle,
+ sepol_port_t * port, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port_ptr);
+
+extern int sepol_port_clone(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_t ** port_ptr);
+
+extern void sepol_port_free(sepol_port_t * port);
+
+#endif
diff --git a/include/sepol/ports.h b/include/sepol/ports.h
new file mode 100644
index 0000000..fb94117
--- /dev/null
+++ b/include/sepol/ports.h
@@ -0,0 +1,40 @@
+#ifndef _SEPOL_PORTS_H_
+#define _SEPOL_PORTS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/port_record.h>
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a port exists */
+extern int sepol_port_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_port_key_t * key, int *response);
+
+/* Query a port - returns the port, or NULL if not found */
+extern int sepol_port_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_port_key_t * key,
+ sepol_port_t ** response);
+
+/* Modify a port, or add it, if the key is not found */
+extern int sepol_port_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_port_key_t * key,
+ const sepol_port_t * data);
+
+/* Iterate the ports
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_port_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_port_t * port,
+ void *fn_arg), void *arg);
+
+#endif
diff --git a/include/sepol/roles.h b/include/sepol/roles.h
new file mode 100644
index 0000000..113f9d2
--- /dev/null
+++ b/include/sepol/roles.h
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_ROLES_H_
+#define _SEPOL_ROLES_H_
+
+extern int sepol_role_exists(const sepol_policydb_t * policydb,
+ const char *role, int *response);
+
+extern int sepol_role_list(const sepol_policydb_t * policydb,
+ char ***roles, unsigned int *nroles);
+
+#endif
diff --git a/include/sepol/sepol.h b/include/sepol/sepol.h
new file mode 100644
index 0000000..c8900d3
--- /dev/null
+++ b/include/sepol/sepol.h
@@ -0,0 +1,28 @@
+#ifndef _SEPOL_H_
+#define _SEPOL_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <sepol/user_record.h>
+#include <sepol/context_record.h>
+#include <sepol/iface_record.h>
+#include <sepol/port_record.h>
+#include <sepol/boolean_record.h>
+#include <sepol/node_record.h>
+
+#include <sepol/booleans.h>
+#include <sepol/interfaces.h>
+#include <sepol/ports.h>
+#include <sepol/nodes.h>
+#include <sepol/users.h>
+#include <sepol/handle.h>
+#include <sepol/debug.h>
+#include <sepol/policydb.h>
+#include <sepol/module.h>
+#include <sepol/context.h>
+
+/* Set internal policydb from a file for subsequent service calls. */
+extern int sepol_set_policydb_from_file(FILE * fp);
+
+#endif
diff --git a/include/sepol/user_record.h b/include/sepol/user_record.h
new file mode 100644
index 0000000..c86ad16
--- /dev/null
+++ b/include/sepol/user_record.h
@@ -0,0 +1,76 @@
+#ifndef _SEPOL_USER_RECORD_H_
+#define _SEPOL_USER_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+
+struct sepol_user;
+struct sepol_user_key;
+typedef struct sepol_user sepol_user_t;
+typedef struct sepol_user_key sepol_user_key_t;
+
+/* Key */
+extern int sepol_user_key_create(sepol_handle_t * handle,
+ const char *name, sepol_user_key_t ** key);
+
+extern void sepol_user_key_unpack(const sepol_user_key_t * key,
+ const char **name);
+
+extern int sepol_user_key_extract(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_key_t ** key_ptr);
+
+extern void sepol_user_key_free(sepol_user_key_t * key);
+
+extern int sepol_user_compare(const sepol_user_t * user,
+ const sepol_user_key_t * key);
+
+extern int sepol_user_compare2(const sepol_user_t * user,
+ const sepol_user_t * user2);
+
+/* Name */
+extern const char *sepol_user_get_name(const sepol_user_t * user);
+
+extern int sepol_user_set_name(sepol_handle_t * handle,
+ sepol_user_t * user, const char *name);
+
+/* MLS */
+extern const char *sepol_user_get_mlslevel(const sepol_user_t * user);
+
+extern int sepol_user_set_mlslevel(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_level);
+
+extern const char *sepol_user_get_mlsrange(const sepol_user_t * user);
+
+extern int sepol_user_set_mlsrange(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_range);
+
+/* Role management */
+extern int sepol_user_get_num_roles(const sepol_user_t * user);
+
+extern int sepol_user_add_role(sepol_handle_t * handle,
+ sepol_user_t * user, const char *role);
+
+extern void sepol_user_del_role(sepol_user_t * user, const char *role);
+
+extern int sepol_user_has_role(const sepol_user_t * user, const char *role);
+
+extern int sepol_user_get_roles(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ const char ***roles_arr,
+ unsigned int *num_roles);
+
+extern int sepol_user_set_roles(sepol_handle_t * handle,
+ sepol_user_t * user,
+ const char **roles_arr, unsigned int num_roles);
+
+/* Create/Clone/Destroy */
+extern int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr);
+
+extern int sepol_user_clone(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_t ** user_ptr);
+
+extern void sepol_user_free(sepol_user_t * user);
+
+#endif
diff --git a/include/sepol/users.h b/include/sepol/users.h
new file mode 100644
index 0000000..01b0775
--- /dev/null
+++ b/include/sepol/users.h
@@ -0,0 +1,57 @@
+#ifndef _SEPOL_USERS_H_
+#define _SEPOL_USERS_H_
+
+#include <sepol/policydb.h>
+#include <sepol/user_record.h>
+#include <sepol/handle.h>
+#include <stddef.h>
+
+/*---------compatibility------------*/
+
+/* Given an existing binary policy (starting at 'data with length 'len')
+ and user configurations living in 'usersdir', generate a new binary
+ policy for the new user configurations. Sets '*newdata' and '*newlen'
+ to refer to the new binary policy image. */
+extern int sepol_genusers(void *data, size_t len,
+ const char *usersdir,
+ void **newdata, size_t * newlen);
+
+/* Enable or disable deletion of users by sepol_genusers(3) when
+ a user in original binary policy image is not defined by the
+ new user configurations. Defaults to disabled. */
+extern void sepol_set_delusers(int on);
+
+/*--------end compatibility----------*/
+
+/* Modify the user, or add it, if the key is not found */
+extern int sepol_user_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_user_key_t * key,
+ const sepol_user_t * data);
+
+/* Return the number of users */
+extern int sepol_user_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified user exists */
+extern int sepol_user_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_user_key_t * key, int *response);
+
+/* Query a user - returns the user or NULL if not found */
+extern int sepol_user_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key,
+ sepol_user_t ** response);
+
+/* Iterate the users
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+extern int sepol_user_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_user_t * user,
+ void *fn_arg), void *arg);
+
+#endif
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 0000000..b96bc94
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,10 @@
+# Installation directories.
+MAN8DIR ?= $(DESTDIR)/usr/share/man/man8
+MAN3DIR ?= $(DESTDIR)/usr/share/man/man3
+
+install:
+ mkdir -p $(MAN3DIR)
+ mkdir -p $(MAN8DIR)
+ install -m 644 man3/*.3 $(MAN3DIR)
+ install -m 644 man8/*.8 $(MAN8DIR)
+
diff --git a/man/man3/sepol_check_context.3 b/man/man3/sepol_check_context.3
new file mode 100644
index 0000000..a63cd56
--- /dev/null
+++ b/man/man3/sepol_check_context.3
@@ -0,0 +1,25 @@
+.TH "sepol_check_context" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_check_context \- Check the validity of a security context against a binary policy.
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_check_context(const char *" context ");"
+.sp
+.BI "int sepol_set_policydb_from_file(FILE *" fp ");"
+
+.SH "DESCRIPTION"
+.B sepol_check_context
+checks the validity of a security context against a binary policy
+previously loaded from a file via
+.B sepol_set_policydb_from_file.
+It is used by
+.B setfiles -c
+to validate a file contexts configuration against the binary policy
+upon policy builds. For validating a context against the active
+policy on a SELinux system, use
+.B security_check_context
+from libselinux instead.
+
+.SH "RETURN VALUE"
+Returns 0 on success or -1 with errno set otherwise.
diff --git a/man/man3/sepol_genbools.3 b/man/man3/sepol_genbools.3
new file mode 100644
index 0000000..0a30137
--- /dev/null
+++ b/man/man3/sepol_genbools.3
@@ -0,0 +1,30 @@
+.TH "sepol_genbools" "3" "11 August 2004" "sds@epoch.ncsc.mil" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genbools(void *" data ", size_t "len ", char *" boolpath );
+.br
+.BI "int sepol_genbools_array(void *" data ", size_t " len ", char **" names ", int *" values ", int " nel );
+
+.SH "DESCRIPTION"
+.B sepol_genbools
+rewrites a binary policy stored in the memory region described by
+(data, len) to use the boolean settings specified in the file named by
+boolpath. The boolean settings are specified by name=value lines
+where value may be 0 or false to disable or 1 or true to enable. The
+binary policy is rewritten in place in memory.
+
+.B sepol_genbools_array
+does likewise, but obtains the boolean settings from the parallel arrays
+(names, values) with nel elements each.
+
+.SH "RETURN VALUE"
+Returns 0 on success or -1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that the boolean file did not exist.
+An errno of EINVAL indicates that one or more booleans listed in the
+boolean file was undefined in the policy or had an invalid value specified;
+in this case, the binary policy is still rewritten but any invalid
+boolean settings are ignored.
+
diff --git a/man/man3/sepol_genusers.3 b/man/man3/sepol_genusers.3
new file mode 100644
index 0000000..05dff00
--- /dev/null
+++ b/man/man3/sepol_genusers.3
@@ -0,0 +1,54 @@
+.TH "sepol_genusers" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genusers \- Generate a new binary policy image with a customized user configuration
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genusers(void *" data ", size_t "len ", const char *" usersdir ", void *" newdata ", size_t *" newlen);
+.sp
+.BI "void sepol_set_delusers(int " on ");"
+
+.SH "DESCRIPTION"
+.B sepol_genusers
+generates a new binary policy image from
+an existing binary policy image stored in the memory region described by
+the starting address
+.I data
+and the length
+.I len
+and a pair of user configuration files named
+.B system.users
+and
+.B local.users
+from the directory specified by
+.I usersdir.
+The resulting binary policy is placed into dynamically allocated
+memory and the variables
+.I newdata
+and
+.I newlen
+are set to refer to the new binary image's starting address and length.
+The original binary policy image is not modified.
+
+By default,
+.B sepol_genusers
+will preserve user entries that are defined in the original binary policy image
+but not defined in the user configuration files. If such user entries
+should instead by omitted entirely from the new binary policy image, then
+the
+.B sepol_set_delusers
+function may be called with
+.I on
+set to 1 prior to calling
+.B sepol_genusers
+in order to enable deletion of such users.
+
+.SH "RETURN VALUE"
+Returns 0 on success or -1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that one or both of the user
+configuration files did not exist. An errno of EINVAL indicates that
+either the original binary policy image or the generated one were
+invalid. An errno of ENOMEM indicates that insufficient memory was
+available to process the original binary policy image or to generate
+the new policy image. Invalid entries in the user configuration files
+are skipped with a warning.
diff --git a/man/man8/chkcon.8 b/man/man8/chkcon.8
new file mode 100644
index 0000000..f8d75df
--- /dev/null
+++ b/man/man8/chkcon.8
@@ -0,0 +1,41 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH CHKCON 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+chkcon \- determine if a security context is valid for a given binary policy
+.SH SYNOPSIS
+chkcon policy_file context
+.SH DESCRIPTION
+This utility validates (the string representation of) a security context
+specified by the argument
+.I context
+against configuration data read in from a policy database binary
+representation file specified by the argument
+.I policy_file.
+.SH FILES
+policy file
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
+
diff --git a/man/man8/genpolbools.8 b/man/man8/genpolbools.8
new file mode 100644
index 0000000..afeaced
--- /dev/null
+++ b/man/man8/genpolbools.8
@@ -0,0 +1,16 @@
+.TH "genpolbools" "8" "11 August 2004" "sds@epoch.ncsc.mil" "SELinux Command Line documentation"
+.SH "NAME"
+genpolbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B genpolbools oldpolicy booleans newpolicy
+
+.SH "DESCRIPTION"
+.B genpolbools
+rewrites an existing binary policy with different boolean settings,
+generating a new binary policy. The booleans file specifies the
+different boolean settings using name=value lines, where value
+can be 0 or false to disable the boolean or 1 or true to enable it.
+
+
+
+
diff --git a/man/man8/genpolusers.8 b/man/man8/genpolusers.8
new file mode 100644
index 0000000..34d729a
--- /dev/null
+++ b/man/man8/genpolusers.8
@@ -0,0 +1,42 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH GENPOLUSERS 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+genpolusers \- Generate new binary policy with updated user configuration
+.SH SYNOPSIS
+genpolusers in-policy usersdir out-policy
+.SH DESCRIPTION
+Given an existing binary policy file
+.I in\-policy,
+generate a new binary policy
+.I out\-policy
+with an updated user configuration based on any
+.B system.users
+and
+.B local.users
+files in the specified
+.I usersdir.
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..73fdef8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,56 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCLUDEDIR ?= $(PREFIX)/include
+LIBDIR ?= $(PREFIX)/lib
+SHLIBDIR ?= $(DESTDIR)/lib
+LIBBASE=$(shell basename $(LIBDIR))
+
+VERSION = $(shell cat ../VERSION)
+LIBVERSION = 1
+
+LIBA=libsepol.a
+TARGET=libsepol.so
+LIBPC=libsepol.pc
+LIBSO=$(TARGET).$(LIBVERSION)
+OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
+LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
+CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-noreturn -Wmissing-format-attribute
+override CFLAGS += -I. -I../include -D_GNU_SOURCE
+
+all: $(LIBA) $(LIBSO) $(LIBPC)
+
+$(LIBA): $(OBJS)
+ $(AR) rcs $@ $^
+ ranlib $@
+
+$(LIBSO): $(LOBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname,$(LIBSO),--version-script=libsepol.map,-z,defs
+ ln -sf $@ $(TARGET)
+
+$(LIBPC): $(LIBPC).in
+ sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@
+
+%.o: %.c
+ $(CC) $(CFLAGS) -fPIC -c -o $@ $<
+
+%.lo: %.c
+ $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $<
+
+install: all
+ test -d $(LIBDIR) || install -m 755 -d $(LIBDIR)
+ install -m 644 $(LIBA) $(LIBDIR)
+ test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR)
+ install -m 755 $(LIBSO) $(SHLIBDIR)
+ test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig
+ install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig
+ cd $(LIBDIR) && ln -sf ../../`basename $(SHLIBDIR)`/$(LIBSO) $(TARGET)
+
+relabel:
+ /sbin/restorecon $(SHLIBDIR)/$(LIBSO)
+
+clean:
+ -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET)
+
+indent:
+ ../../scripts/Lindent $(wildcard *.[ch])
+
diff --git a/src/assertion.c b/src/assertion.c
new file mode 100644
index 0000000..a6e0c04
--- /dev/null
+++ b/src/assertion.c
@@ -0,0 +1,151 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Assertion checker for avtab entries, taken from
+ * checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+
+static int check_assertion_helper(sepol_handle_t * handle,
+ policydb_t * p,
+ avtab_t * te_avtab, avtab_t * te_cond_avtab,
+ unsigned int stype, unsigned int ttype,
+ class_perm_node_t * perm, unsigned long line)
+{
+ avtab_key_t avkey;
+ avtab_ptr_t node;
+ class_perm_node_t *curperm;
+
+ for (curperm = perm; curperm != NULL; curperm = curperm->next) {
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = curperm->class;
+ avkey.specified = AVTAB_ALLOWED;
+ for (node = avtab_search_node(te_avtab, &avkey);
+ node != NULL;
+ node = avtab_search_node_next(node, avkey.specified)) {
+ if (node->datum.data & curperm->data)
+ goto err;
+ }
+ for (node = avtab_search_node(te_cond_avtab, &avkey);
+ node != NULL;
+ node = avtab_search_node_next(node, avkey.specified)) {
+ if (node->datum.data & curperm->data)
+ goto err;
+ }
+ }
+
+ return 0;
+
+ err:
+ if (line) {
+ ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
+ line, p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->class - 1],
+ sepol_av_to_string(p, curperm->class,
+ node->datum.data & curperm->data));
+ } else {
+ ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
+ p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->class - 1],
+ sepol_av_to_string(p, curperm->class,
+ node->datum.data & curperm->data));
+ }
+ return -1;
+}
+
+int check_assertions(sepol_handle_t * handle, policydb_t * p,
+ avrule_t * avrules)
+{
+ avrule_t *a;
+ avtab_t te_avtab, te_cond_avtab;
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ int rc;
+
+ if (!avrules) {
+ /* Since assertions are stored in avrules, if it is NULL
+ there won't be any to check. This also prevents an invalid
+ free if the avtabs are never initialized */
+ return 0;
+ }
+
+ if (avrules) {
+ if (avtab_init(&te_avtab))
+ goto oom;
+ if (avtab_init(&te_cond_avtab)) {
+ avtab_destroy(&te_avtab);
+ goto oom;
+ }
+ if (expand_avtab(p, &p->te_avtab, &te_avtab) ||
+ expand_avtab(p, &p->te_cond_avtab, &te_cond_avtab)) {
+ avtab_destroy(&te_avtab);
+ avtab_destroy(&te_cond_avtab);
+ goto oom;
+ }
+ }
+
+ for (a = avrules; a != NULL; a = a->next) {
+ ebitmap_t *stypes = &a->stypes.types;
+ ebitmap_t *ttypes = &a->ttypes.types;
+
+ if (!(a->specified & AVRULE_NEVERALLOW))
+ continue;
+
+ ebitmap_for_each_bit(stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ if (a->flags & RULE_SELF) {
+ if (check_assertion_helper
+ (handle, p, &te_avtab, &te_cond_avtab, i, i,
+ a->perms, a->line)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ ebitmap_for_each_bit(ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ if (check_assertion_helper
+ (handle, p, &te_avtab, &te_cond_avtab, i, j,
+ a->perms, a->line)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ }
+ }
+
+ rc = 0;
+out:
+ avtab_destroy(&te_avtab);
+ avtab_destroy(&te_cond_avtab);
+ return rc;
+
+ oom:
+ ERR(handle, "Out of memory - unable to check neverallows");
+ return -1;
+}
diff --git a/src/av_permissions.h b/src/av_permissions.h
new file mode 100644
index 0000000..97278ed
--- /dev/null
+++ b/src/av_permissions.h
@@ -0,0 +1,3 @@
+/* Used by security_compute_av. */
+#define PROCESS__TRANSITION 0x00000002UL
+#define PROCESS__DYNTRANSITION 0x00800000UL
diff --git a/src/avrule_block.c b/src/avrule_block.c
new file mode 100644
index 0000000..16c89f3
--- /dev/null
+++ b/src/avrule_block.c
@@ -0,0 +1,202 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Functions that manipulate a logical block (conditional, optional,
+ * or global scope) for a policy module.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+/* It is anticipated that there be less declarations within an avrule
+ * block than the global policy. Thus the symbol table sizes are
+ * smaller than those listed in policydb.c */
+static unsigned int symtab_sizes[SYM_NUM] = {
+ 2,
+ 4,
+ 8,
+ 32,
+ 16,
+ 4,
+ 2,
+ 2,
+};
+
+avrule_block_t *avrule_block_create(void)
+{
+ avrule_block_t *block;
+ if ((block = calloc(1, sizeof(*block))) == NULL) {
+ return NULL;
+ }
+ return block;
+}
+
+avrule_decl_t *avrule_decl_create(uint32_t decl_id)
+{
+ avrule_decl_t *decl;
+ int i;
+ if ((decl = calloc(1, sizeof(*decl))) == NULL) {
+ return NULL;
+ }
+ decl->decl_id = decl_id;
+ for (i = 0; i < SYM_NUM; i++) {
+ if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
+ avrule_decl_destroy(decl);
+ free(decl);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_init(&decl->required.scope[i]);
+ ebitmap_init(&decl->declared.scope[i]);
+ }
+ return decl;
+}
+
+/* note that unlike the other destroy functions, this one does /NOT/
+ * destroy the pointer itself */
+static void scope_index_destroy(scope_index_t * scope)
+{
+ unsigned int i;
+ if (scope == NULL) {
+ return;
+ }
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_destroy(scope->scope + i);
+ }
+ for (i = 0; i < scope->class_perms_len; i++) {
+ ebitmap_destroy(scope->class_perms_map + i);
+ }
+ free(scope->class_perms_map);
+}
+
+void avrule_decl_destroy(avrule_decl_t * x)
+{
+ if (x == NULL) {
+ return;
+ }
+ cond_list_destroy(x->cond_list);
+ avrule_list_destroy(x->avrules);
+ role_trans_rule_list_destroy(x->role_tr_rules);
+ filename_trans_rule_list_destroy(x->filename_trans_rules);
+ role_allow_rule_list_destroy(x->role_allow_rules);
+ range_trans_rule_list_destroy(x->range_tr_rules);
+ scope_index_destroy(&x->required);
+ scope_index_destroy(&x->declared);
+ symtabs_destroy(x->symtab);
+ free(x->module_name);
+ free(x);
+}
+
+void avrule_block_destroy(avrule_block_t * x)
+{
+ avrule_decl_t *decl;
+ if (x == NULL) {
+ return;
+ }
+ decl = x->branch_list;
+ while (decl != NULL) {
+ avrule_decl_t *next_decl = decl->next;
+ avrule_decl_destroy(decl);
+ decl = next_decl;
+ }
+ free(x);
+}
+
+void avrule_block_list_destroy(avrule_block_t * x)
+{
+ while (x != NULL) {
+ avrule_block_t *next = x->next;
+ avrule_block_destroy(x);
+ x = next;
+ }
+}
+
+/* Get a conditional node from a avrule_decl with the same expression.
+ * If that expression does not exist then create one. */
+cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl,
+ cond_list_t * cond)
+{
+ cond_list_t *result;
+ int was_created;
+ result = cond_node_find(p, cond, decl->cond_list, &was_created);
+ if (result != NULL && was_created) {
+ result->next = decl->cond_list;
+ decl->cond_list = result;
+ }
+ return result;
+}
+
+/* Look up an identifier in a policy's scoping table. If it is there,
+ * marked as SCOPE_DECL, and any of its declaring block has been enabled,
+ * then return 1. Otherwise return 0. Can only be called after the
+ * decl_val_to_struct index has been created */
+int is_id_enabled(char *id, policydb_t * p, int symbol_table)
+{
+ scope_datum_t *scope =
+ (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id);
+ uint32_t i;
+ if (scope == NULL) {
+ return 0;
+ }
+ if (scope->scope != SCOPE_DECL) {
+ return 0;
+ }
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ avrule_decl_t *decl =
+ p->decl_val_to_struct[scope->decl_ids[i] - 1];
+ if (decl != NULL && decl->enabled) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Check if a particular permission is present within the given class,
+ * and that the class is enabled. Returns 1 if both conditions are
+ * true, 0 if neither could be found or if the class id disabled. */
+int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p)
+{
+ class_datum_t *cladatum;
+ perm_datum_t *perm;
+ if (!is_id_enabled(class_id, p, SYM_CLASSES)) {
+ return 0;
+ }
+ cladatum =
+ (class_datum_t *) hashtab_search(p->p_classes.table, class_id);
+ if (cladatum == NULL) {
+ return 0;
+ }
+ perm = hashtab_search(cladatum->permissions.table, perm_id);
+ if (perm == NULL && cladatum->comdatum != 0) {
+ /* permission was not in this class. before giving
+ * up, check the class's parent */
+ perm =
+ hashtab_search(cladatum->comdatum->permissions.table,
+ perm_id);
+ }
+ if (perm == NULL) {
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/avtab.c b/src/avtab.c
new file mode 100644
index 0000000..ea947cb
--- /dev/null
+++ b/src/avtab.c
@@ -0,0 +1,531 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Code cleanup
+ *
+ * Updated: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ * Copyright (C) 2003,2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the access vector table type.
+ */
+
+#include <stdlib.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/errcodes.h>
+
+#include "debug.h"
+#include "private.h"
+
+static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask)
+{
+ return ((keyp->target_class + (keyp->target_type << 2) +
+ (keyp->source_type << 9)) & mask);
+}
+
+static avtab_ptr_t
+avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
+ avtab_datum_t * datum)
+{
+ avtab_ptr_t newnode;
+ newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
+ if (newnode == NULL)
+ return NULL;
+ memset(newnode, 0, sizeof(struct avtab_node));
+ newnode->key = *key;
+ newnode->datum = *datum;
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+
+ h->nel++;
+ return newnode;
+}
+
+int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+ int hvalue;
+ avtab_ptr_t prev, cur, newnode;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return SEPOL_ENOMEM;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (prev = NULL, cur = h->htable[hvalue];
+ cur; prev = cur, cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return SEPOL_EEXIST;
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+ if (!newnode)
+ return SEPOL_ENOMEM;
+
+ return 0;
+}
+
+/* Unlike avtab_insert(), this function allow multiple insertions of the same
+ * key/specified mask into the table, as needed by the conditional avtab.
+ * It also returns a pointer to the node inserted.
+ */
+avtab_ptr_t
+avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+ int hvalue;
+ avtab_ptr_t prev, cur, newnode;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+ hvalue = avtab_hash(key, h->mask);
+ for (prev = NULL, cur = h->htable[hvalue];
+ cur; prev = cur, cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ break;
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+
+ return newnode;
+}
+
+avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key)
+{
+ int hvalue;
+ avtab_ptr_t cur;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return &cur->datum;
+
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+
+ return NULL;
+}
+
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key)
+{
+ int hvalue;
+ avtab_ptr_t cur;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return cur;
+
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+ return NULL;
+}
+
+avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified)
+{
+ avtab_ptr_t cur;
+
+ if (!node)
+ return NULL;
+
+ specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+ for (cur = node->next; cur; cur = cur->next) {
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type == cur->key.target_type &&
+ node->key.target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return cur;
+
+ if (node->key.source_type < cur->key.source_type)
+ break;
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type < cur->key.target_type)
+ break;
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type == cur->key.target_type &&
+ node->key.target_class < cur->key.target_class)
+ break;
+ }
+ return NULL;
+}
+
+void avtab_destroy(avtab_t * h)
+{
+ unsigned int i;
+ avtab_ptr_t cur, temp;
+
+ if (!h || !h->htable)
+ return;
+
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ free(temp);
+ }
+ h->htable[i] = NULL;
+ }
+ free(h->htable);
+ h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
+}
+
+int avtab_map(avtab_t * h,
+ int (*apply) (avtab_key_t * k,
+ avtab_datum_t * d, void *args), void *args)
+{
+ unsigned int i;
+ int ret;
+ avtab_ptr_t cur;
+
+ if (!h)
+ return 0;
+
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(&cur->key, &cur->datum, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+int avtab_init(avtab_t * h)
+{
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
+
+int avtab_alloc(avtab_t *h, uint32_t nrules)
+{
+ uint16_t mask = 0;
+ uint32_t shift = 0;
+ uint32_t work = nrules;
+ uint32_t nslot = 0;
+
+ if (nrules == 0)
+ goto out;
+
+ while (work) {
+ work = work >> 1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE)
+ nslot = MAX_AVTAB_SIZE;
+ mask = nslot - 1;
+
+ h->htable = calloc(nslot, sizeof(avtab_ptr_t));
+ if (!h->htable)
+ return -1;
+out:
+ h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ return 0;
+}
+
+void avtab_hash_eval(avtab_t * h, char *tag)
+{
+ unsigned int i, chain_len, slots_used, max_chain_len;
+ avtab_ptr_t cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len);
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+ AVTAB_ALLOWED,
+ AVTAB_AUDITDENY,
+ AVTAB_AUDITALLOW,
+ AVTAB_TRANSITION,
+ AVTAB_CHANGE,
+ AVTAB_MEMBER
+};
+
+int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+ int (*insertf) (avtab_t * a, avtab_key_t * k,
+ avtab_datum_t * d, void *p), void *p)
+{
+ uint16_t buf16[4], enabled;
+ uint32_t buf32[7], items, items2, val;
+ avtab_key_t key;
+ avtab_datum_t datum;
+ unsigned set;
+ unsigned int i;
+ int rc;
+
+ memset(&key, 0, sizeof(avtab_key_t));
+ memset(&datum, 0, sizeof(avtab_datum_t));
+
+ if (vers < POLICYDB_VERSION_AVTAB) {
+ rc = next_entry(buf32, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ items2 = le32_to_cpu(buf32[0]);
+
+ if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) {
+ ERR(fp->handle, "invalid item count");
+ return -1;
+ }
+
+ rc = next_entry(buf32, fp, sizeof(uint32_t) * items2);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+
+ items = 0;
+ val = le32_to_cpu(buf32[items++]);
+ key.source_type = (uint16_t) val;
+ if (key.source_type != val) {
+ ERR(fp->handle, "truncated source type");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_type = (uint16_t) val;
+ if (key.target_type != val) {
+ ERR(fp->handle, "truncated target type");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_class = (uint16_t) val;
+ if (key.target_class != val) {
+ ERR(fp->handle, "truncated target class");
+ return -1;
+ }
+
+ val = le32_to_cpu(buf32[items++]);
+ enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+ if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+ ERR(fp->handle, "null entry");
+ return -1;
+ }
+ if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+ ERR(fp->handle, "entry has both access "
+ "vectors and types");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+ if (val & spec_order[i]) {
+ key.specified = spec_order[i] | enabled;
+ datum.data = le32_to_cpu(buf32[items++]);
+ rc = insertf(a, &key, &datum, p);
+ if (rc)
+ return rc;
+ }
+ }
+
+ if (items != items2) {
+ ERR(fp->handle, "entry only had %d items, "
+ "expected %d", items2, items);
+ return -1;
+ }
+ return 0;
+ }
+
+ rc = next_entry(buf16, fp, sizeof(uint16_t) * 4);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ items = 0;
+ key.source_type = le16_to_cpu(buf16[items++]);
+ key.target_type = le16_to_cpu(buf16[items++]);
+ key.target_class = le16_to_cpu(buf16[items++]);
+ key.specified = le16_to_cpu(buf16[items++]);
+
+ set = 0;
+ for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+ if (key.specified & spec_order[i])
+ set++;
+ }
+ if (!set || set > 1) {
+ ERR(fp->handle, "more than one specifier");
+ return -1;
+ }
+
+ rc = next_entry(buf32, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ datum.data = le32_to_cpu(*buf32);
+ return insertf(a, &key, &datum, p);
+}
+
+static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d,
+ void *p __attribute__ ((unused)))
+{
+ return avtab_insert(a, k, d);
+}
+
+int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
+{
+ unsigned int i;
+ int rc;
+ uint32_t buf[1];
+ uint32_t nel;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated table");
+ goto bad;
+ }
+ nel = le32_to_cpu(buf[0]);
+ if (!nel) {
+ ERR(fp->handle, "table is empty");
+ goto bad;
+ }
+
+ rc = avtab_alloc(a, nel);
+ if (rc) {
+ ERR(fp->handle, "out of memory");
+ goto bad;
+ }
+
+ for (i = 0; i < nel; i++) {
+ rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
+ if (rc) {
+ if (rc == SEPOL_ENOMEM)
+ ERR(fp->handle, "out of memory");
+ if (rc == SEPOL_EEXIST)
+ ERR(fp->handle, "duplicate entry");
+ ERR(fp->handle, "failed on entry %d of %u", i, nel);
+ goto bad;
+ }
+ }
+
+ return 0;
+
+ bad:
+ avtab_destroy(a);
+ return -1;
+}
diff --git a/src/boolean_internal.h b/src/boolean_internal.h
new file mode 100644
index 0000000..aad7ade
--- /dev/null
+++ b/src/boolean_internal.h
@@ -0,0 +1,16 @@
+#ifndef _SEPOL_BOOLEAN_INTERNAL_H_
+#define _SEPOL_BOOLEAN_INTERNAL_H_
+
+#include <sepol/boolean_record.h>
+#include <sepol/booleans.h>
+#include "dso.h"
+
+hidden_proto(sepol_bool_key_create)
+ hidden_proto(sepol_bool_key_unpack)
+ hidden_proto(sepol_bool_get_name)
+ hidden_proto(sepol_bool_set_name)
+ hidden_proto(sepol_bool_get_value)
+ hidden_proto(sepol_bool_set_value)
+ hidden_proto(sepol_bool_create)
+ hidden_proto(sepol_bool_free)
+#endif
diff --git a/src/boolean_record.c b/src/boolean_record.c
new file mode 100644
index 0000000..8b64413
--- /dev/null
+++ b/src/boolean_record.c
@@ -0,0 +1,180 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "boolean_internal.h"
+#include "debug.h"
+
+struct sepol_bool {
+ /* This boolean's name */
+ char *name;
+
+ /* Its value */
+ int value;
+};
+
+struct sepol_bool_key {
+ /* This boolean's name */
+ const char *name;
+};
+
+int sepol_bool_key_create(sepol_handle_t * handle,
+ const char *name, sepol_bool_key_t ** key_ptr)
+{
+
+ sepol_bool_key_t *tmp_key =
+ (sepol_bool_key_t *) malloc(sizeof(struct sepol_bool_key));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, " "could not create boolean key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_key_create)
+
+void sepol_bool_key_unpack(const sepol_bool_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_bool_key_unpack)
+
+int sepol_bool_key_extract(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_key_t ** key_ptr)
+{
+
+ if (sepol_bool_key_create(handle, boolean->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from boolean %s",
+ boolean->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_bool_key_free(sepol_bool_key_t * key)
+{
+ free(key);
+}
+
+int sepol_bool_compare(const sepol_bool_t * boolean,
+ const sepol_bool_key_t * key)
+{
+
+ return strcmp(boolean->name, key->name);
+}
+
+int sepol_bool_compare2(const sepol_bool_t * boolean,
+ const sepol_bool_t * boolean2)
+{
+
+ return strcmp(boolean->name, boolean2->name);
+}
+
+/* Name */
+const char *sepol_bool_get_name(const sepol_bool_t * boolean)
+{
+
+ return boolean->name;
+}
+
+hidden_def(sepol_bool_get_name)
+
+int sepol_bool_set_name(sepol_handle_t * handle,
+ sepol_bool_t * boolean, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, could not set boolean name");
+ return STATUS_ERR;
+ }
+ free(boolean->name);
+ boolean->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_set_name)
+
+/* Value */
+int sepol_bool_get_value(const sepol_bool_t * boolean)
+{
+
+ return boolean->value;
+}
+
+hidden_def(sepol_bool_get_value)
+
+void sepol_bool_set_value(sepol_bool_t * boolean, int value)
+{
+
+ boolean->value = value;
+}
+
+hidden_def(sepol_bool_set_value)
+
+/* Create */
+int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr)
+{
+
+ sepol_bool_t *boolean = (sepol_bool_t *) malloc(sizeof(sepol_bool_t));
+
+ if (!boolean) {
+ ERR(handle, "out of memory, "
+ "could not create boolean record");
+ return STATUS_ERR;
+ }
+
+ boolean->name = NULL;
+ boolean->value = 0;
+
+ *bool_ptr = boolean;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_create)
+
+/* Deep copy clone */
+int sepol_bool_clone(sepol_handle_t * handle,
+ const sepol_bool_t * boolean, sepol_bool_t ** bool_ptr)
+{
+
+ sepol_bool_t *new_bool = NULL;
+
+ if (sepol_bool_create(handle, &new_bool) < 0)
+ goto err;
+
+ if (sepol_bool_set_name(handle, new_bool, boolean->name) < 0)
+ goto err;
+
+ new_bool->value = boolean->value;
+
+ *bool_ptr = new_bool;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone boolean record");
+ sepol_bool_free(new_bool);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_bool_free(sepol_bool_t * boolean)
+{
+
+ if (!boolean)
+ return;
+
+ free(boolean->name);
+ free(boolean);
+}
+
+hidden_def(sepol_bool_free)
diff --git a/src/booleans.c b/src/booleans.c
new file mode 100644
index 0000000..03f8c98
--- /dev/null
+++ b/src/booleans.c
@@ -0,0 +1,216 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "handle.h"
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/booleans.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include "boolean_internal.h"
+
+static int bool_update(sepol_handle_t * handle,
+ policydb_t * policydb,
+ const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+ const char *cname;
+ char *name;
+ int value;
+
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+ value = sepol_bool_get_value(data);
+
+ if (!name)
+ goto omem;
+
+ cond_bool_datum_t *datum =
+ hashtab_search(policydb->p_bools.table, name);
+ if (!datum) {
+ ERR(handle, "boolean %s no longer in policy", name);
+ goto err;
+ }
+ if (value != 0 && value != 1) {
+ ERR(handle, "illegal value %d for boolean %s", value, name);
+ goto err;
+ }
+
+ free(name);
+ datum->state = value;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(name);
+ ERR(handle, "could not update boolean %s", cname);
+ return STATUS_ERR;
+}
+
+static int bool_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ int bool_idx, sepol_bool_t ** record)
+{
+
+ const char *name = policydb->p_bool_val_to_name[bool_idx];
+ cond_bool_datum_t *booldatum = policydb->bool_val_to_struct[bool_idx];
+ int value = booldatum->state;
+
+ sepol_bool_t *tmp_record = NULL;
+
+ if (sepol_bool_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_bool_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ sepol_bool_set_value(tmp_record, value);
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert boolean %s to record", name);
+ sepol_bool_free(tmp_record);
+ return STATUS_ERR;
+}
+
+int sepol_bool_set(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+ const char *name;
+ sepol_bool_key_unpack(key, &name);
+
+ policydb_t *policydb = &p->p;
+ if (bool_update(handle, policydb, key, data) < 0)
+ goto err;
+
+ if (evaluate_conds(policydb) < 0) {
+ ERR(handle, "error while re-evaluating conditionals");
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not set boolean %s", name);
+ return STATUS_ERR;
+}
+
+int sepol_bool_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ *response = policydb->p_bools.nprim;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+int sepol_bool_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+
+ const char *cname;
+ char *name = NULL;
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+
+ if (!name) {
+ ERR(handle, "out of memory, could not check "
+ "if user %s exists", cname);
+ return STATUS_ERR;
+ }
+
+ *response = (hashtab_search(policydb->p_bools.table, name) != NULL);
+ free(name);
+ return STATUS_SUCCESS;
+}
+
+int sepol_bool_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key, sepol_bool_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ cond_bool_datum_t *booldatum = NULL;
+
+ const char *cname;
+ char *name = NULL;
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+
+ if (!name)
+ goto omem;
+
+ booldatum = hashtab_search(policydb->p_bools.table, name);
+ if (!booldatum) {
+ *response = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (bool_to_record(handle, policydb,
+ booldatum->s.value - 1, response) < 0)
+ goto err;
+
+ free(name);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not query boolean %s", cname);
+ free(name);
+ return STATUS_ERR;
+}
+
+int sepol_bool_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_bool_t * boolean,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ unsigned int nbools = policydb->p_bools.nprim;
+ sepol_bool_t *boolean = NULL;
+ unsigned int i;
+
+ /* For each boolean */
+ for (i = 0; i < nbools; i++) {
+
+ int status;
+
+ if (bool_to_record(handle, policydb, i, &boolean) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(boolean, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_bool_free(boolean);
+ boolean = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over booleans");
+ sepol_bool_free(boolean);
+ return STATUS_ERR;
+}
diff --git a/src/conditional.c b/src/conditional.c
new file mode 100644
index 0000000..1482387
--- /dev/null
+++ b/src/conditional.c
@@ -0,0 +1,905 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ * Frank Mayer <mayerf@tresys.com>
+ * David Caplan <dac@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/conditional.h>
+
+#include "private.h"
+
+/* move all type rules to top of t/f lists to help kernel on evaluation */
+static void cond_optimize(cond_av_list_t ** l)
+{
+ cond_av_list_t *top, *p, *cur;
+
+ top = p = cur = *l;
+
+ while (cur) {
+ if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
+ p->next = cur->next;
+ cur->next = top;
+ top = cur;
+ cur = p->next;
+ } else {
+ p = cur;
+ cur = cur->next;
+ }
+ }
+ *l = top;
+}
+
+/* reorder t/f lists for kernel */
+void cond_optimize_lists(cond_list_t * cl)
+{
+ cond_list_t *n;
+
+ for (n = cl; n != NULL; n = n->next) {
+ cond_optimize(&n->true_list);
+ cond_optimize(&n->false_list);
+ }
+}
+
+static int bool_present(unsigned int target, unsigned int bools[],
+ unsigned int num_bools)
+{
+ unsigned int i = 0;
+ int ret = 1;
+
+ if (num_bools > COND_MAX_BOOLS) {
+ return 0;
+ }
+ while (i < num_bools && target != bools[i])
+ i++;
+ if (i == num_bools)
+ ret = 0; /* got to end w/o match */
+ return ret;
+}
+
+static int same_bools(cond_node_t * a, cond_node_t * b)
+{
+ unsigned int i, x;
+
+ x = a->nbools;
+
+ /* same number of bools? */
+ if (x != b->nbools)
+ return 0;
+
+ /* make sure all the bools in a are also in b */
+ for (i = 0; i < x; i++)
+ if (!bool_present(a->bool_ids[i], b->bool_ids, x))
+ return 0;
+ return 1;
+}
+
+/*
+ * Determine if two conditional expressions are equal.
+ */
+int cond_expr_equal(cond_node_t * a, cond_node_t * b)
+{
+ cond_expr_t *cur_a, *cur_b;
+
+ if (a == NULL || b == NULL)
+ return 0;
+
+ if (a->nbools != b->nbools)
+ return 0;
+
+ /* if exprs have <= COND_MAX_BOOLS we can check the precompute values
+ * for the expressions.
+ */
+ if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
+ if (!same_bools(a, b))
+ return 0;
+ return (a->expr_pre_comp == b->expr_pre_comp);
+ }
+
+ /* for long expressions we check for exactly the same expression */
+ cur_a = a->expr;
+ cur_b = b->expr;
+ while (1) {
+ if (cur_a == NULL && cur_b == NULL)
+ return 1;
+ else if (cur_a == NULL || cur_b == NULL)
+ return 0;
+ if (cur_a->expr_type != cur_b->expr_type)
+ return 0;
+ if (cur_a->expr_type == COND_BOOL) {
+ if (cur_a->bool != cur_b->bool)
+ return 0;
+ }
+ cur_a = cur_a->next;
+ cur_b = cur_b->next;
+ }
+ return 1;
+}
+
+/* Create a new conditional node, optionally copying
+ * the conditional expression from an existing node.
+ * If node is NULL then a new node will be created
+ * with no conditional expression.
+ */
+cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
+{
+ cond_node_t *new_node;
+ unsigned int i;
+
+ new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
+ if (!new_node) {
+ return NULL;
+ }
+ memset(new_node, 0, sizeof(cond_node_t));
+
+ if (node) {
+ new_node->expr = cond_copy_expr(node->expr);
+ if (!new_node->expr) {
+ free(new_node);
+ return NULL;
+ }
+ new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
+ new_node->nbools = node->nbools;
+ for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
+ new_node->bool_ids[i] = node->bool_ids[i];
+ new_node->expr_pre_comp = node->expr_pre_comp;
+ }
+
+ return new_node;
+}
+
+/* Find a conditional (the needle) within a list of existing ones (the
+ * haystack) that has a matching expression. If found, return a
+ * pointer to the existing node, setting 'was_created' to 0.
+ * Otherwise create a new one and return it, setting 'was_created' to
+ * 1. */
+cond_node_t *cond_node_find(policydb_t * p,
+ cond_node_t * needle, cond_node_t * haystack,
+ int *was_created)
+{
+ while (haystack) {
+ if (cond_expr_equal(needle, haystack)) {
+ *was_created = 0;
+ return haystack;
+ }
+ haystack = haystack->next;
+ }
+ *was_created = 1;
+
+ return cond_node_create(p, needle);
+}
+
+/* return either a pre-existing matching node or create a new node */
+cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+ cond_node_t * cn)
+{
+ int was_created;
+ cond_node_t *result = cond_node_find(p, cn, list, &was_created);
+ if (result != NULL && was_created) {
+ /* add conditional node to policy list */
+ result->next = p->cond_list;
+ p->cond_list = result;
+ }
+ return result;
+}
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
+{
+
+ cond_expr_t *cur;
+ int s[COND_EXPR_MAXDEPTH];
+ int sp = -1;
+
+ s[0] = -1;
+
+ for (cur = expr; cur != NULL; cur = cur->next) {
+ switch (cur->expr_type) {
+ case COND_BOOL:
+ if (sp == (COND_EXPR_MAXDEPTH - 1))
+ return -1;
+ sp++;
+ s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+ break;
+ case COND_NOT:
+ if (sp < 0)
+ return -1;
+ s[sp] = !s[sp];
+ break;
+ case COND_OR:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] |= s[sp + 1];
+ break;
+ case COND_AND:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] &= s[sp + 1];
+ break;
+ case COND_XOR:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] ^= s[sp + 1];
+ break;
+ case COND_EQ:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] = (s[sp] == s[sp + 1]);
+ break;
+ case COND_NEQ:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] = (s[sp] != s[sp + 1]);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return s[0];
+}
+
+cond_expr_t *cond_copy_expr(cond_expr_t * expr)
+{
+ cond_expr_t *cur, *head, *tail, *new_expr;
+ tail = head = NULL;
+ cur = expr;
+ while (cur) {
+ new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
+ if (!new_expr)
+ goto free_head;
+ memset(new_expr, 0, sizeof(cond_expr_t));
+
+ new_expr->expr_type = cur->expr_type;
+ new_expr->bool = cur->bool;
+
+ if (!head)
+ head = new_expr;
+ if (tail)
+ tail->next = new_expr;
+ tail = new_expr;
+ cur = cur->next;
+ }
+ return head;
+
+ free_head:
+ while (head) {
+ tail = head->next;
+ free(head);
+ head = tail;
+ }
+ return NULL;
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a cond_node_t and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
+{
+ int new_state;
+ cond_av_list_t *cur;
+
+ new_state = cond_evaluate_expr(p, node->expr);
+ if (new_state != node->cur_state) {
+ node->cur_state = new_state;
+ if (new_state == -1)
+ printf
+ ("expression result was undefined - disabling all rules.\n");
+ /* turn the rules on or off */
+ for (cur = node->true_list; cur != NULL; cur = cur->next) {
+ if (new_state <= 0) {
+ cur->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ cur->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+
+ for (cur = node->false_list; cur != NULL; cur = cur->next) {
+ /* -1 or 1 */
+ if (new_state) {
+ cur->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ cur->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+ }
+ return 0;
+}
+
+/* precompute and simplify an expression if possible. If left with !expression, change
+ * to expression and switch t and f. precompute expression for expressions with limited
+ * number of bools.
+ */
+int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
+{
+ cond_expr_t *ne, *e;
+ cond_av_list_t *tmp;
+ unsigned int i, j, orig_value[COND_MAX_BOOLS];
+ int k;
+ uint32_t test = 0x0;
+ avrule_t *tmp2;
+
+ cn->nbools = 0;
+
+ memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
+ cn->expr_pre_comp = 0x0;
+
+ /* take care of !expr case */
+ ne = NULL;
+ e = cn->expr;
+
+ /* becuase it's RPN look at last element */
+ while (e->next != NULL) {
+ ne = e;
+ e = e->next;
+ }
+ if (e->expr_type == COND_NOT) {
+ if (ne) {
+ ne->next = NULL;
+ } else { /* ne should never be NULL */
+ printf
+ ("Found expr with no bools and only a ! - this should never happen.\n");
+ return -1;
+ }
+ /* swap the true and false lists */
+ tmp = cn->true_list;
+ cn->true_list = cn->false_list;
+ cn->false_list = tmp;
+ tmp2 = cn->avtrue_list;
+ cn->avtrue_list = cn->avfalse_list;
+ cn->avfalse_list = tmp2;
+
+ /* free the "not" node in the list */
+ free(e);
+ }
+
+ /* find all the bools in the expression */
+ for (e = cn->expr; e != NULL; e = e->next) {
+ switch (e->expr_type) {
+ case COND_BOOL:
+ i = 0;
+ /* see if we've already seen this bool */
+ if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) {
+ /* count em all but only record up to COND_MAX_BOOLS */
+ if (cn->nbools < COND_MAX_BOOLS)
+ cn->bool_ids[cn->nbools++] = e->bool;
+ else
+ cn->nbools++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* only precompute for exprs with <= COND_AX_BOOLS */
+ if (cn->nbools <= COND_MAX_BOOLS) {
+ /* save the default values for the bools so we can play with them */
+ for (i = 0; i < cn->nbools; i++) {
+ orig_value[i] =
+ p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
+ }
+
+ /* loop through all possible combinations of values for bools in expression */
+ for (test = 0x0; test < (0x1U << cn->nbools); test++) {
+ /* temporarily set the value for all the bools in the
+ * expression using the corr. bit in test */
+ for (j = 0; j < cn->nbools; j++) {
+ p->bool_val_to_struct[cn->bool_ids[j] -
+ 1]->state =
+ (test & (0x1 << j)) ? 1 : 0;
+ }
+ k = cond_evaluate_expr(p, cn->expr);
+ if (k == -1) {
+ printf
+ ("While testing expression, expression result "
+ "was undefined - this should never happen.\n");
+ return -1;
+ }
+ /* set the bit if expression evaluates true */
+ if (k)
+ cn->expr_pre_comp |= 0x1 << test;
+ }
+
+ /* restore bool default values */
+ for (i = 0; i < cn->nbools; i++)
+ p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
+ orig_value[i];
+ }
+ return 0;
+}
+
+int evaluate_conds(policydb_t * p)
+{
+ int ret;
+ cond_node_t *cur;
+
+ for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+ ret = evaluate_cond_node(p, cur);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int cond_policydb_init(policydb_t * p)
+{
+ p->bool_val_to_struct = NULL;
+ p->cond_list = NULL;
+ if (avtab_init(&p->te_cond_avtab))
+ return -1;
+
+ return 0;
+}
+
+void cond_av_list_destroy(cond_av_list_t * list)
+{
+ cond_av_list_t *cur, *next;
+ for (cur = list; cur != NULL; cur = next) {
+ next = cur->next;
+ /* the avtab_ptr_t node is destroy by the avtab */
+ free(cur);
+ }
+}
+
+void cond_expr_destroy(cond_expr_t * expr)
+{
+ cond_expr_t *cur_expr, *next_expr;
+
+ if (!expr)
+ return;
+
+ for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
+ next_expr = cur_expr->next;
+ free(cur_expr);
+ }
+}
+
+void cond_node_destroy(cond_node_t * node)
+{
+ if (!node)
+ return;
+
+ cond_expr_destroy(node->expr);
+ avrule_list_destroy(node->avtrue_list);
+ avrule_list_destroy(node->avfalse_list);
+ cond_av_list_destroy(node->true_list);
+ cond_av_list_destroy(node->false_list);
+}
+
+void cond_list_destroy(cond_list_t * list)
+{
+ cond_node_t *next, *cur;
+
+ if (list == NULL)
+ return;
+
+ for (cur = list; cur != NULL; cur = next) {
+ next = cur->next;
+ cond_node_destroy(cur);
+ free(cur);
+ }
+}
+
+void cond_policydb_destroy(policydb_t * p)
+{
+ if (p->bool_val_to_struct != NULL)
+ free(p->bool_val_to_struct);
+ avtab_destroy(&p->te_cond_avtab);
+ cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(policydb_t * p)
+{
+ if (p->bool_val_to_struct)
+ free(p->bool_val_to_struct);
+ p->bool_val_to_struct = (cond_bool_datum_t **)
+ malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *));
+ if (!p->bool_val_to_struct)
+ return -1;
+ return 0;
+}
+
+int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ free(datum);
+ return 0;
+}
+
+int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ cond_bool_datum_t *booldatum;
+
+ booldatum = datum;
+ p = datap;
+
+ if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
+ return -EINVAL;
+
+ p->p_bool_val_to_name[booldatum->s.value - 1] = key;
+ p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
+
+ return 0;
+}
+
+static int bool_isvalid(cond_bool_datum_t * b)
+{
+ if (!(b->state == 0 || b->state == 1))
+ return 0;
+ return 1;
+}
+
+int cond_read_bool(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ cond_bool_datum_t *booldatum;
+ uint32_t buf[3], len;
+ int rc;
+
+ booldatum = malloc(sizeof(cond_bool_datum_t));
+ if (!booldatum)
+ return -1;
+ memset(booldatum, 0, sizeof(cond_bool_datum_t));
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto err;
+
+ booldatum->s.value = le32_to_cpu(buf[0]);
+ booldatum->state = le32_to_cpu(buf[1]);
+
+ if (!bool_isvalid(booldatum))
+ goto err;
+
+ len = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto err;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto err;
+ key[len] = 0;
+ if (hashtab_insert(h, key, booldatum))
+ goto err;
+
+ return 0;
+ err:
+ cond_destroy_bool(key, booldatum, 0);
+ return -1;
+}
+
+struct cond_insertf_data {
+ struct policydb *p;
+ cond_av_list_t *other;
+ cond_av_list_t *head;
+ cond_av_list_t *tail;
+};
+
+static int cond_insertf(avtab_t * a
+ __attribute__ ((unused)), avtab_key_t * k,
+ avtab_datum_t * d, void *ptr)
+{
+ struct cond_insertf_data *data = ptr;
+ struct policydb *p = data->p;
+ cond_av_list_t *other = data->other, *list, *cur;
+ avtab_ptr_t node_ptr;
+ uint8_t found;
+
+ /*
+ * For type rules we have to make certain there aren't any
+ * conflicting rules by searching the te_avtab and the
+ * cond_te_avtab.
+ */
+ if (k->specified & AVTAB_TYPE) {
+ if (avtab_search(&p->te_avtab, k)) {
+ printf
+ ("security: type rule already exists outside of a conditional.");
+ goto err;
+ }
+ /*
+ * If we are reading the false list other will be a pointer to
+ * the true list. We can have duplicate entries if there is only
+ * 1 other entry and it is in our true list.
+ *
+ * If we are reading the true list (other == NULL) there shouldn't
+ * be any other entries.
+ */
+ if (other) {
+ node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+ if (node_ptr) {
+ if (avtab_search_node_next
+ (node_ptr, k->specified)) {
+ printf
+ ("security: too many conflicting type rules.");
+ goto err;
+ }
+ found = 0;
+ for (cur = other; cur != NULL; cur = cur->next) {
+ if (cur->node == node_ptr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printf
+ ("security: conflicting type rules.\n");
+ goto err;
+ }
+ }
+ } else {
+ if (avtab_search(&p->te_cond_avtab, k)) {
+ printf
+ ("security: conflicting type rules when adding type rule for true.\n");
+ goto err;
+ }
+ }
+ }
+
+ node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+ if (!node_ptr) {
+ printf("security: could not insert rule.");
+ goto err;
+ }
+ node_ptr->parse_context = (void *)1;
+
+ list = malloc(sizeof(cond_av_list_t));
+ if (!list)
+ goto err;
+ memset(list, 0, sizeof(cond_av_list_t));
+
+ list->node = node_ptr;
+ if (!data->head)
+ data->head = list;
+ else
+ data->tail->next = list;
+ data->tail = list;
+ return 0;
+
+ err:
+ cond_av_list_destroy(data->head);
+ data->head = NULL;
+ return -1;
+}
+
+static int cond_read_av_list(policydb_t * p, void *fp,
+ cond_av_list_t ** ret_list, cond_av_list_t * other)
+{
+ unsigned int i;
+ int rc;
+ uint32_t buf[1], len;
+ struct cond_insertf_data data;
+
+ *ret_list = NULL;
+
+ len = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+ if (len == 0) {
+ return 0;
+ }
+
+ data.p = p;
+ data.other = other;
+ data.head = NULL;
+ data.tail = NULL;
+ for (i = 0; i < len; i++) {
+ rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
+ cond_insertf, &data);
+ if (rc)
+ return rc;
+
+ }
+
+ *ret_list = data.head;
+ return 0;
+}
+
+static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
+{
+ if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
+ printf
+ ("security: conditional expressions uses unknown operator.\n");
+ return 0;
+ }
+
+ if (expr->bool > p->p_bools.nprim) {
+ printf
+ ("security: conditional expressions uses unknown bool.\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
+{
+ uint32_t buf[2];
+ int len, i, rc;
+ cond_expr_t *expr = NULL, *last = NULL;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+
+ node->cur_state = le32_to_cpu(buf[0]);
+
+ len = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+
+ /* expr */
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto err;
+
+ expr = malloc(sizeof(cond_expr_t));
+ if (!expr) {
+ goto err;
+ }
+ memset(expr, 0, sizeof(cond_expr_t));
+
+ expr->expr_type = le32_to_cpu(buf[0]);
+ expr->bool = le32_to_cpu(buf[1]);
+
+ if (!expr_isvalid(p, expr)) {
+ free(expr);
+ goto err;
+ }
+
+ if (i == 0) {
+ node->expr = expr;
+ } else {
+ last->next = expr;
+ }
+ last = expr;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+ goto err;
+ if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
+ != 0)
+ goto err;
+ } else {
+ if (avrule_read_list(p, &node->avtrue_list, fp))
+ goto err;
+ if (avrule_read_list(p, &node->avfalse_list, fp))
+ goto err;
+ }
+
+ return 0;
+ err:
+ cond_node_destroy(node);
+ free(node);
+ return -1;
+}
+
+int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
+{
+ cond_node_t *node, *last = NULL;
+ uint32_t buf[1];
+ int i, len, rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+
+ rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
+ if (rc)
+ goto err;
+
+ for (i = 0; i < len; i++) {
+ node = malloc(sizeof(cond_node_t));
+ if (!node)
+ goto err;
+ memset(node, 0, sizeof(cond_node_t));
+
+ if (cond_read_node(p, node, fp) != 0)
+ goto err;
+
+ if (i == 0) {
+ *list = node;
+ } else {
+ last->next = node;
+ }
+ last = node;
+ }
+ return 0;
+ err:
+ return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result
+ */
+void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+ struct sepol_av_decision *avd)
+{
+ avtab_ptr_t node;
+
+ if (!ctab || !key || !avd)
+ return;
+
+ for (node = avtab_search_node(ctab, key); node != NULL;
+ node = avtab_search_node_next(node, key->specified)) {
+ if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
+ avd->allowed |= node->datum.data;
+ if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
+ /* Since a '0' in an auditdeny mask represents a
+ * permission we do NOT want to audit (dontaudit), we use
+ * the '&' operand to ensure that all '0's in the mask
+ * are retained (much unlike the allow and auditallow cases).
+ */
+ avd->auditdeny &= node->datum.data;
+ if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
+ avd->auditallow |= node->datum.data;
+ }
+ return;
+}
+
+avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+ cond_av_list_t * cond_list)
+{
+
+ cond_av_list_t *cur_av;
+
+ for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
+
+ if (cur_av->node->key.source_type == key->source_type &&
+ cur_av->node->key.target_type == key->target_type &&
+ cur_av->node->key.target_class == key->target_class)
+
+ return &cur_av->node->datum;
+
+ }
+ return NULL;
+
+}
diff --git a/src/constraint.c b/src/constraint.c
new file mode 100644
index 0000000..7154019
--- /dev/null
+++ b/src/constraint.c
@@ -0,0 +1,47 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask_types.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+int constraint_expr_init(constraint_expr_t * expr)
+{
+ memset(expr, 0, sizeof(*expr));
+ ebitmap_init(&expr->names);
+ if ((expr->type_names = malloc(sizeof(*expr->type_names))) == NULL) {
+ return -1;
+ }
+ type_set_init(expr->type_names);
+ return 0;
+}
+
+void constraint_expr_destroy(constraint_expr_t * expr)
+{
+ if (expr != NULL) {
+ ebitmap_destroy(&expr->names);
+ type_set_destroy(expr->type_names);
+ free(expr->type_names);
+ free(expr);
+ }
+}
diff --git a/src/context.c b/src/context.c
new file mode 100644
index 0000000..84dad34
--- /dev/null
+++ b/src/context.c
@@ -0,0 +1,338 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include "context_internal.h"
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+#include "mls.h"
+
+/* ----- Compatibility ---- */
+int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+ return context_is_valid(p, c);
+}
+
+int sepol_check_context(const char *context)
+{
+
+ return sepol_context_to_sid((const sepol_security_context_t)context,
+ strlen(context) + 1, NULL);
+}
+
+/* ---- End compatibility --- */
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid. Return 0 otherwise.
+ */
+int context_is_valid(const policydb_t * p, const context_struct_t * c)
+{
+
+ role_datum_t *role;
+ user_datum_t *usrdatum;
+ ebitmap_t types, roles;
+ int ret = 1;
+
+ ebitmap_init(&types);
+ ebitmap_init(&roles);
+ if (!c->role || c->role > p->p_roles.nprim)
+ return 0;
+
+ if (!c->user || c->user > p->p_users.nprim)
+ return 0;
+
+ if (!c->type || c->type > p->p_types.nprim)
+ return 0;
+
+ if (c->role != OBJECT_R_VAL) {
+ /*
+ * Role must be authorized for the type.
+ */
+ role = p->role_val_to_struct[c->role - 1];
+ if (!ebitmap_get_bit(&role->cache, c->type - 1))
+ /* role may not be associated with type */
+ return 0;
+
+ /*
+ * User must be authorized for the role.
+ */
+ usrdatum = p->user_val_to_struct[c->user - 1];
+ if (!usrdatum)
+ return 0;
+
+ if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
+ /* user may not be associated with role */
+ return 0;
+ }
+
+ if (!mls_context_isvalid(p, c))
+ return 0;
+
+ return ret;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int context_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ char **result, size_t * result_len)
+{
+
+ char *scontext = NULL;
+ size_t scontext_len = 0;
+ char *ptr;
+
+ /* Compute the size of the context. */
+ scontext_len +=
+ strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
+ scontext_len +=
+ strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
+ scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
+ scontext_len += mls_compute_context_len(policydb, context);
+
+ /* We must null terminate the string */
+ scontext_len += 1;
+
+ /* Allocate space for the context; caller must free this space. */
+ scontext = malloc(scontext_len);
+ if (!scontext)
+ goto omem;
+ scontext[scontext_len - 1] = '\0';
+
+ /*
+ * Copy the user name, role name and type name into the context.
+ */
+ ptr = scontext;
+ sprintf(ptr, "%s:%s:%s",
+ policydb->p_user_val_to_name[context->user - 1],
+ policydb->p_role_val_to_name[context->role - 1],
+ policydb->p_type_val_to_name[context->type - 1]);
+
+ ptr +=
+ strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
+ strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
+ strlen(policydb->p_type_val_to_name[context->type - 1]);
+
+ mls_sid_to_context(policydb, context, &ptr);
+
+ *result = scontext;
+ *result_len = scontext_len;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not convert " "context to string");
+ free(scontext);
+ return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the given record
+ */
+int context_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const sepol_context_t * record)
+{
+
+ context_struct_t *scontext = NULL;
+ user_datum_t *usrdatum;
+ role_datum_t *roldatum;
+ type_datum_t *typdatum;
+
+ /* Hashtab keys are not constant - suppress warnings */
+ char *user = strdup(sepol_context_get_user(record));
+ char *role = strdup(sepol_context_get_role(record));
+ char *type = strdup(sepol_context_get_type(record));
+ const char *mls = sepol_context_get_mls(record);
+
+ scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
+ if (!user || !role || !type || !scontext) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+ context_init(scontext);
+
+ /* User */
+ usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
+ (hashtab_key_t) user);
+ if (!usrdatum) {
+ ERR(handle, "user %s is not defined", user);
+ goto err_destroy;
+ }
+ scontext->user = usrdatum->s.value;
+
+ /* Role */
+ roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
+ (hashtab_key_t) role);
+ if (!roldatum) {
+ ERR(handle, "role %s is not defined", role);
+ goto err_destroy;
+ }
+ scontext->role = roldatum->s.value;
+
+ /* Type */
+ typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
+ (hashtab_key_t) type);
+ if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
+ ERR(handle, "type %s is not defined", type);
+ goto err_destroy;
+ }
+ scontext->type = typdatum->s.value;
+
+ /* MLS */
+ if (mls && !policydb->mls) {
+ ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
+ mls);
+ goto err_destroy;
+ } else if (!mls && policydb->mls) {
+ ERR(handle, "MLS is enabled, but no MLS context found");
+ goto err_destroy;
+ }
+ if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
+ goto err_destroy;
+
+ /* Validity check */
+ if (!context_is_valid(policydb, scontext)) {
+ if (mls) {
+ ERR(handle,
+ "invalid security context: \"%s:%s:%s:%s\"",
+ user, role, type, mls);
+ } else {
+ ERR(handle,
+ "invalid security context: \"%s:%s:%s\"",
+ user, role, type);
+ }
+ goto err_destroy;
+ }
+
+ *cptr = scontext;
+ free(user);
+ free(type);
+ free(role);
+ return STATUS_SUCCESS;
+
+ err_destroy:
+ errno = EINVAL;
+ context_destroy(scontext);
+
+ err:
+ free(scontext);
+ free(user);
+ free(type);
+ free(role);
+ ERR(handle, "could not create context structure");
+ return STATUS_ERR;
+}
+
+/*
+ * Create a record from the given context structure
+ */
+int context_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ sepol_context_t ** record)
+{
+
+ sepol_context_t *tmp_record = NULL;
+ char *mls = NULL;
+
+ if (sepol_context_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_context_set_user(handle, tmp_record,
+ policydb->p_user_val_to_name[context->user -
+ 1]) < 0)
+ goto err;
+
+ if (sepol_context_set_role(handle, tmp_record,
+ policydb->p_role_val_to_name[context->role -
+ 1]) < 0)
+ goto err;
+
+ if (sepol_context_set_type(handle, tmp_record,
+ policydb->p_type_val_to_name[context->type -
+ 1]) < 0)
+ goto err;
+
+ if (policydb->mls) {
+ if (mls_to_string(handle, policydb, context, &mls) < 0)
+ goto err;
+
+ if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
+ goto err;
+ }
+
+ free(mls);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not create context record");
+ sepol_context_free(tmp_record);
+ free(mls);
+ return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the provided string.
+ */
+int context_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const char *con_str, size_t con_str_len)
+{
+
+ char *con_cpy = NULL;
+ sepol_context_t *ctx_record = NULL;
+
+ /* sepol_context_from_string expects a NULL-terminated string */
+ con_cpy = malloc(con_str_len + 1);
+ if (!con_cpy)
+ goto omem;
+ memcpy(con_cpy, con_str, con_str_len);
+ con_cpy[con_str_len] = '\0';
+
+ if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
+ goto err;
+
+ /* Now create from the data structure */
+ if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
+ goto err;
+
+ free(con_cpy);
+ sepol_context_free(ctx_record);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not create context structure");
+ free(con_cpy);
+ sepol_context_free(ctx_record);
+ return STATUS_ERR;
+}
+
+int sepol_context_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_context_t * context)
+{
+
+ context_struct_t *con = NULL;
+ int ret = context_from_record(handle, &policydb->p, &con, context);
+ context_destroy(con);
+ free(con);
+ return ret;
+}
diff --git a/src/context.h b/src/context.h
new file mode 100644
index 0000000..d25ca8a
--- /dev/null
+++ b/src/context.h
@@ -0,0 +1,37 @@
+#ifndef _SEPOL_INTERNAL_CONTEXT_H_
+#define _SEPOL_INTERNAL_CONTEXT_H_
+
+#include <stddef.h>
+#include "context_internal.h"
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/handle.h>
+
+/* Create a context structure from high level representation */
+extern int context_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const sepol_context_t * data);
+
+extern int context_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ sepol_context_t ** record);
+
+/* Create a context structure from string representation */
+extern int context_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const char *con_str, size_t con_str_len);
+
+/* Check if the provided context is valid for this policy */
+extern int context_is_valid(const policydb_t * policydb,
+ const context_struct_t * context);
+
+/* Extract the context as string */
+extern int context_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ char **result, size_t * result_len);
+
+#endif
diff --git a/src/context_internal.h b/src/context_internal.h
new file mode 100644
index 0000000..7987c1c
--- /dev/null
+++ b/src/context_internal.h
@@ -0,0 +1,19 @@
+#ifndef _SEPOL_CONTEXT_INTERNAL_H_
+#define _SEPOL_CONTEXT_INTERNAL_H_
+
+#include <sepol/context_record.h>
+#include "dso.h"
+
+hidden_proto(sepol_context_clone)
+ hidden_proto(sepol_context_create)
+ hidden_proto(sepol_context_free)
+ hidden_proto(sepol_context_from_string)
+ hidden_proto(sepol_context_get_mls)
+ hidden_proto(sepol_context_get_role)
+ hidden_proto(sepol_context_get_type)
+ hidden_proto(sepol_context_get_user)
+ hidden_proto(sepol_context_set_mls)
+ hidden_proto(sepol_context_set_role)
+ hidden_proto(sepol_context_set_type)
+ hidden_proto(sepol_context_set_user)
+#endif
diff --git a/src/context_record.c b/src/context_record.c
new file mode 100644
index 0000000..ac2884a
--- /dev/null
+++ b/src/context_record.c
@@ -0,0 +1,324 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_context {
+
+ /* Selinux user */
+ char *user;
+
+ /* Selinux role */
+ char *role;
+
+ /* Selinux type */
+ char *type;
+
+ /* MLS */
+ char *mls;
+};
+
+/* User */
+const char *sepol_context_get_user(const sepol_context_t * con)
+{
+
+ return con->user;
+}
+
+hidden_def(sepol_context_get_user)
+
+int sepol_context_set_user(sepol_handle_t * handle,
+ sepol_context_t * con, const char *user)
+{
+
+ char *tmp_user = strdup(user);
+ if (!tmp_user) {
+ ERR(handle, "out of memory, could not set "
+ "context user to %s", user);
+ return STATUS_ERR;
+ }
+
+ free(con->user);
+ con->user = tmp_user;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_user)
+
+/* Role */
+const char *sepol_context_get_role(const sepol_context_t * con)
+{
+
+ return con->role;
+}
+
+hidden_def(sepol_context_get_role)
+
+int sepol_context_set_role(sepol_handle_t * handle,
+ sepol_context_t * con, const char *role)
+{
+
+ char *tmp_role = strdup(role);
+ if (!tmp_role) {
+ ERR(handle, "out of memory, could not set "
+ "context role to %s", role);
+ return STATUS_ERR;
+ }
+ free(con->role);
+ con->role = tmp_role;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_role)
+
+/* Type */
+const char *sepol_context_get_type(const sepol_context_t * con)
+{
+
+ return con->type;
+}
+
+hidden_def(sepol_context_get_type)
+
+int sepol_context_set_type(sepol_handle_t * handle,
+ sepol_context_t * con, const char *type)
+{
+
+ char *tmp_type = strdup(type);
+ if (!tmp_type) {
+ ERR(handle, "out of memory, could not set "
+ "context type to %s", type);
+ return STATUS_ERR;
+ }
+ free(con->type);
+ con->type = tmp_type;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_type)
+
+/* MLS */
+const char *sepol_context_get_mls(const sepol_context_t * con)
+{
+
+ return con->mls;
+}
+
+hidden_def(sepol_context_get_mls)
+
+int sepol_context_set_mls(sepol_handle_t * handle,
+ sepol_context_t * con, const char *mls)
+{
+
+ char *tmp_mls = strdup(mls);
+ if (!tmp_mls) {
+ ERR(handle, "out of memory, could not set "
+ "MLS fields to %s", mls);
+ return STATUS_ERR;
+ }
+ free(con->mls);
+ con->mls = tmp_mls;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_mls)
+
+/* Create */
+int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
+{
+
+ sepol_context_t *con =
+ (sepol_context_t *) malloc(sizeof(sepol_context_t));
+
+ if (!con) {
+ ERR(handle, "out of memory, could not " "create context\n");
+ return STATUS_ERR;
+ }
+
+ con->user = NULL;
+ con->role = NULL;
+ con->type = NULL;
+ con->mls = NULL;
+ *con_ptr = con;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_create)
+
+/* Deep copy clone */
+int sepol_context_clone(sepol_handle_t * handle,
+ const sepol_context_t * con, sepol_context_t ** con_ptr)
+{
+
+ sepol_context_t *new_con = NULL;
+
+ if (!con) {
+ *con_ptr = NULL;
+ return 0;
+ }
+
+ if (sepol_context_create(handle, &new_con) < 0)
+ goto err;
+
+ if (!(new_con->user = strdup(con->user)))
+ goto omem;
+
+ if (!(new_con->role = strdup(con->role)))
+ goto omem;
+
+ if (!(new_con->type = strdup(con->type)))
+ goto omem;
+
+ if (con->mls && !(new_con->mls = strdup(con->mls)))
+ goto omem;
+
+ *con_ptr = new_con;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not clone context record");
+ sepol_context_free(new_con);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_context_clone)
+
+/* Destroy */
+void sepol_context_free(sepol_context_t * con)
+{
+
+ if (!con)
+ return;
+
+ free(con->user);
+ free(con->role);
+ free(con->type);
+ free(con->mls);
+ free(con);
+}
+
+hidden_def(sepol_context_free)
+
+int sepol_context_from_string(sepol_handle_t * handle,
+ const char *str, sepol_context_t ** con)
+{
+
+ char *tmp = NULL, *low, *high;
+ sepol_context_t *tmp_con = NULL;
+
+ if (!strcmp(str, "<<none>>")) {
+ *con = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (sepol_context_create(handle, &tmp_con) < 0)
+ goto err;
+
+ /* Working copy context */
+ tmp = strdup(str);
+ if (!tmp) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+ low = tmp;
+
+ /* Then, break it into its components */
+
+ /* User */
+ if (!(high = strchr(low, ':')))
+ goto mcontext;
+ else
+ *high++ = '\0';
+ if (sepol_context_set_user(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+
+ /* Role */
+ if (!(high = strchr(low, ':')))
+ goto mcontext;
+ else
+ *high++ = '\0';
+ if (sepol_context_set_role(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+
+ /* Type, and possibly MLS */
+ if (!(high = strchr(low, ':'))) {
+ if (sepol_context_set_type(handle, tmp_con, low) < 0)
+ goto err;
+ } else {
+ *high++ = '\0';
+ if (sepol_context_set_type(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+ if (sepol_context_set_mls(handle, tmp_con, low) < 0)
+ goto err;
+ }
+
+ free(tmp);
+ *con = tmp_con;
+
+ return STATUS_SUCCESS;
+
+ mcontext:
+ errno = EINVAL;
+ ERR(handle, "malformed context \"%s\"", str);
+
+ err:
+ ERR(handle, "could not construct context from string");
+ free(tmp);
+ sepol_context_free(tmp_con);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_context_from_string)
+
+int sepol_context_to_string(sepol_handle_t * handle,
+ const sepol_context_t * con, char **str_ptr)
+{
+
+ int rc;
+ const int user_sz = strlen(con->user);
+ const int role_sz = strlen(con->role);
+ const int type_sz = strlen(con->type);
+ const int mls_sz = (con->mls) ? strlen(con->mls) : 0;
+ const int total_sz = user_sz + role_sz + type_sz +
+ mls_sz + ((con->mls) ? 3 : 2);
+
+ char *str = (char *)malloc(total_sz + 1);
+ if (!str)
+ goto omem;
+
+ if (con->mls) {
+ rc = snprintf(str, total_sz + 1, "%s:%s:%s:%s",
+ con->user, con->role, con->type, con->mls);
+ if (rc < 0 || (rc >= total_sz + 1)) {
+ ERR(handle, "print error");
+ goto err;
+ }
+ } else {
+ rc = snprintf(str, total_sz + 1, "%s:%s:%s",
+ con->user, con->role, con->type);
+ if (rc < 0 || (rc >= total_sz + 1)) {
+ ERR(handle, "print error");
+ goto err;
+ }
+ }
+
+ *str_ptr = str;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not convert context to string");
+ free(str);
+ return STATUS_ERR;
+}
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..51918fd
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,89 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "handle.h"
+#include "debug.h"
+
+/* Deprecated */
+struct sepol_handle sepol_compat_handle = {
+ .msg_callback = sepol_msg_default_handler,
+ .msg_callback_arg = NULL,
+};
+
+void sepol_debug(int on)
+{
+ sepol_compat_handle.msg_callback = (on) ?
+ sepol_msg_default_handler : NULL;
+}
+
+/* End deprecated */
+
+int sepol_msg_get_level(sepol_handle_t * handle)
+{
+ return handle->msg_level;
+}
+
+hidden_def(sepol_msg_get_level)
+
+const char *sepol_msg_get_channel(sepol_handle_t * handle)
+{
+ return handle->msg_channel;
+}
+
+hidden_def(sepol_msg_get_channel)
+
+const char *sepol_msg_get_fname(sepol_handle_t * handle)
+{
+ return handle->msg_fname;
+}
+
+hidden_def(sepol_msg_get_fname)
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+void hidden sepol_msg_default_handler(void *varg __attribute__ ((unused)),
+ sepol_handle_t * handle,
+ const char *fmt, ...)
+{
+
+ FILE *stream = NULL;
+
+ switch (sepol_msg_get_level(handle)) {
+
+ case SEPOL_MSG_ERR:
+ case SEPOL_MSG_WARN:
+ stream = stderr;
+ break;
+ case SEPOL_MSG_INFO:
+ default:
+ stream = stdout;
+ break;
+ }
+
+ fprintf(stream, "%s.%s: ",
+ sepol_msg_get_channel(handle), sepol_msg_get_fname(handle));
+
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stream, fmt, ap);
+ va_end(ap);
+
+ fprintf(stream, "\n");
+
+ varg = NULL;
+}
+
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t *
+ handle,
+ const char *fmt, ...),
+ void *msg_callback_arg)
+{
+
+ handle->msg_callback = msg_callback;
+ handle->msg_callback_arg = msg_callback_arg;
+}
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..56b397b
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_INTERNAL_DEBUG_H_
+#define _SEPOL_INTERNAL_DEBUG_H_
+
+#include <stdio.h>
+#include <sepol/debug.h>
+#include "dso.h"
+#include "handle.h"
+
+#define STATUS_SUCCESS 0
+#define STATUS_ERR -1
+#define STATUS_NODATA 1
+
+/* FIXME: this needs to become a real function. Declaring variables
+ * in a macro is _evil_ as it can shadow other variables in local scope.
+ * The variable h has been renamed to _sepol_h to reduce this chance, but
+ * it is still wrong.
+ */
+#define msg_write(handle_arg, level_arg, \
+ channel_arg, func_arg, ...) do { \
+ sepol_handle_t *_sepol_h = (handle_arg) ?: &sepol_compat_handle; \
+ if (_sepol_h->msg_callback) { \
+ _sepol_h->msg_fname = func_arg; \
+ _sepol_h->msg_channel = channel_arg; \
+ _sepol_h->msg_level = level_arg; \
+ \
+ _sepol_h->msg_callback( \
+ _sepol_h->msg_callback_arg, \
+ _sepol_h, __VA_ARGS__); \
+ } \
+ } while(0)
+
+#define ERR(handle, ...) \
+ msg_write(handle, SEPOL_MSG_ERR, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#define INFO(handle, ...) \
+ msg_write(handle, SEPOL_MSG_INFO, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#define WARN(handle, ...) \
+ msg_write(handle, SEPOL_MSG_WARN, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 3, 4)))
+#endif
+extern void hidden sepol_msg_default_handler(void *varg,
+ sepol_handle_t * msg,
+ const char *fmt, ...);
+
+extern struct sepol_handle sepol_compat_handle;
+
+hidden_proto(sepol_msg_get_channel)
+ hidden_proto(sepol_msg_get_fname)
+ hidden_proto(sepol_msg_get_level)
+#endif
diff --git a/src/dso.h b/src/dso.h
new file mode 100644
index 0000000..5c69aae
--- /dev/null
+++ b/src/dso.h
@@ -0,0 +1,23 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H 1
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal) \
+ extern __typeof (fct) internal; \
+ extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/src/ebitmap.c b/src/ebitmap.c
new file mode 100644
index 0000000..cc6a915
--- /dev/null
+++ b/src/ebitmap.c
@@ -0,0 +1,368 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the extensible bitmap type.
+ */
+
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "private.h"
+
+int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2, *new, *prev;
+
+ ebitmap_init(dst);
+
+ n1 = e1->node;
+ n2 = e2->node;
+ prev = 0;
+ while (n1 || n2) {
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new) {
+ ebitmap_destroy(dst);
+ return -ENOMEM;
+ }
+ memset(new, 0, sizeof(ebitmap_node_t));
+ if (n1 && n2 && n1->startbit == n2->startbit) {
+ new->startbit = n1->startbit;
+ new->map = n1->map | n2->map;
+ n1 = n1->next;
+ n2 = n2->next;
+ } else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
+ new->startbit = n1->startbit;
+ new->map = n1->map;
+ n1 = n1->next;
+ } else {
+ new->startbit = n2->startbit;
+ new->map = n2->map;
+ n2 = n2->next;
+ }
+
+ new->next = 0;
+ if (prev)
+ prev->next = new;
+ else
+ dst->node = new;
+ prev = new;
+ }
+
+ dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
+ return 0;
+}
+
+int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1)
+{
+ ebitmap_t tmp;
+
+ if (ebitmap_or(&tmp, dst, e1))
+ return -1;
+ ebitmap_destroy(dst);
+ dst->node = tmp.node;
+ dst->highbit = tmp.highbit;
+
+ return 0;
+}
+
+int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2;
+
+ if (e1->highbit != e2->highbit)
+ return 0;
+
+ n1 = e1->node;
+ n2 = e2->node;
+ while (n1 && n2 &&
+ (n1->startbit == n2->startbit) && (n1->map == n2->map)) {
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+
+ if (n1 || n2)
+ return 0;
+
+ return 1;
+}
+
+int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src)
+{
+ ebitmap_node_t *n, *new, *prev;
+
+ ebitmap_init(dst);
+ n = src->node;
+ prev = 0;
+ while (n) {
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new) {
+ ebitmap_destroy(dst);
+ return -ENOMEM;
+ }
+ memset(new, 0, sizeof(ebitmap_node_t));
+ new->startbit = n->startbit;
+ new->map = n->map;
+ new->next = 0;
+ if (prev)
+ prev->next = new;
+ else
+ dst->node = new;
+ prev = new;
+ n = n->next;
+ }
+
+ dst->highbit = src->highbit;
+ return 0;
+}
+
+int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2;
+
+ if (e1->highbit < e2->highbit)
+ return 0;
+
+ n1 = e1->node;
+ n2 = e2->node;
+ while (n1 && n2 && (n1->startbit <= n2->startbit)) {
+ if (n1->startbit < n2->startbit) {
+ n1 = n1->next;
+ continue;
+ }
+ if ((n1->map & n2->map) != n2->map)
+ return 0;
+
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+
+ if (n2)
+ return 0;
+
+ return 1;
+}
+
+int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
+{
+ ebitmap_node_t *n;
+
+ if (e->highbit < bit)
+ return 0;
+
+ n = e->node;
+ while (n && (n->startbit <= bit)) {
+ if ((n->startbit + MAPSIZE) > bit) {
+ if (n->map & (MAPBIT << (bit - n->startbit)))
+ return 1;
+ else
+ return 0;
+ }
+ n = n->next;
+ }
+
+ return 0;
+}
+
+int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value)
+{
+ ebitmap_node_t *n, *prev, *new;
+ uint32_t startbit = bit & ~(MAPSIZE - 1);
+ uint32_t highbit = startbit + MAPSIZE;
+
+ if (highbit == 0) {
+ ERR(NULL, "bitmap overflow, bit 0x%x", bit);
+ return -EINVAL;
+ }
+
+ prev = 0;
+ n = e->node;
+ while (n && n->startbit <= bit) {
+ if ((n->startbit + MAPSIZE) > bit) {
+ if (value) {
+ n->map |= (MAPBIT << (bit - n->startbit));
+ } else {
+ n->map &= ~(MAPBIT << (bit - n->startbit));
+ if (!n->map) {
+ /* drop this node from the bitmap */
+
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
+ if (prev)
+ e->highbit =
+ prev->startbit +
+ MAPSIZE;
+ else
+ e->highbit = 0;
+ }
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+
+ free(n);
+ }
+ }
+ return 0;
+ }
+ prev = n;
+ n = n->next;
+ }
+
+ if (!value)
+ return 0;
+
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new)
+ return -ENOMEM;
+ memset(new, 0, sizeof(ebitmap_node_t));
+
+ new->startbit = startbit;
+ new->map = (MAPBIT << (bit - new->startbit));
+
+ if (!n) {
+ /* this node will be the highest map within the bitmap */
+ e->highbit = highbit;
+ }
+
+ if (prev) {
+ new->next = prev->next;
+ prev->next = new;
+ } else {
+ new->next = e->node;
+ e->node = new;
+ }
+
+ return 0;
+}
+
+void ebitmap_destroy(ebitmap_t * e)
+{
+ ebitmap_node_t *n, *temp;
+
+ if (!e)
+ return;
+
+ n = e->node;
+ while (n) {
+ temp = n;
+ n = n->next;
+ free(temp);
+ }
+
+ e->highbit = 0;
+ e->node = 0;
+ return;
+}
+
+int ebitmap_read(ebitmap_t * e, void *fp)
+{
+ int rc;
+ ebitmap_node_t *n, *l;
+ uint32_t buf[3], mapsize, count, i;
+ uint64_t map;
+
+ ebitmap_init(e);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto bad;
+
+ mapsize = le32_to_cpu(buf[0]);
+ e->highbit = le32_to_cpu(buf[1]);
+ count = le32_to_cpu(buf[2]);
+
+ if (mapsize != MAPSIZE) {
+ printf
+ ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n",
+ mapsize, MAPSIZE, e->highbit);
+ goto bad;
+ }
+ if (!e->highbit) {
+ e->node = NULL;
+ goto ok;
+ }
+ if (e->highbit & (MAPSIZE - 1)) {
+ printf
+ ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n",
+ e->highbit, MAPSIZE);
+ goto bad;
+ }
+ l = NULL;
+ for (i = 0; i < count; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ printf("security: ebitmap: truncated map\n");
+ goto bad;
+ }
+ n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!n) {
+ printf("security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(n, 0, sizeof(ebitmap_node_t));
+
+ n->startbit = le32_to_cpu(buf[0]);
+
+ if (n->startbit & (MAPSIZE - 1)) {
+ printf
+ ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n",
+ n->startbit, MAPSIZE);
+ goto bad_free;
+ }
+ if (n->startbit > (e->highbit - MAPSIZE)) {
+ printf
+ ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n",
+ n->startbit, (e->highbit - MAPSIZE));
+ goto bad_free;
+ }
+ rc = next_entry(&map, fp, sizeof(uint64_t));
+ if (rc < 0) {
+ printf("security: ebitmap: truncated map\n");
+ goto bad_free;
+ }
+ n->map = le64_to_cpu(map);
+
+ if (!n->map) {
+ printf
+ ("security: ebitmap: null map in ebitmap (startbit %d)\n",
+ n->startbit);
+ goto bad_free;
+ }
+ if (l) {
+ if (n->startbit <= l->startbit) {
+ printf
+ ("security: ebitmap: start bit %d comes after start bit %d\n",
+ n->startbit, l->startbit);
+ goto bad_free;
+ }
+ l->next = n;
+ } else
+ e->node = n;
+
+ l = n;
+ }
+
+ ok:
+ rc = 0;
+ out:
+ return rc;
+ bad_free:
+ free(n);
+ bad:
+ if (!rc)
+ rc = -EINVAL;
+ ebitmap_destroy(e);
+ goto out;
+}
+
+/* FLASK */
diff --git a/src/expand.c b/src/expand.c
new file mode 100644
index 0000000..b42acbe
--- /dev/null
+++ b/src/expand.c
@@ -0,0 +1,3179 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "context.h"
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+#include "private.h"
+
+typedef struct expand_state {
+ int verbose;
+ uint32_t *typemap;
+ uint32_t *boolmap;
+ uint32_t *rolemap;
+ uint32_t *usermap;
+ policydb_t *base;
+ policydb_t *out;
+ sepol_handle_t *handle;
+ int expand_neverallow;
+} expand_state_t;
+
+static void expand_state_init(expand_state_t * state)
+{
+ memset(state, 0, sizeof(expand_state_t));
+}
+
+static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
+{
+ unsigned int i;
+ ebitmap_node_t *tnode;
+ ebitmap_init(dst);
+
+ ebitmap_for_each_bit(src, tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ if (!map[i])
+ continue;
+ if (ebitmap_set_bit(dst, map[i] - 1, 1))
+ return -1;
+ }
+ return 0;
+}
+
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *type, *new_type;
+ expand_state_t *state;
+
+ id = (char *)key;
+ type = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if ((type->flavor == TYPE_TYPE && !type->primary)
+ || type->flavor == TYPE_ALIAS) {
+ /* aliases are handled later */
+ return 0;
+ }
+ if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying type or attribute %s", id);
+
+ new_id = strdup(id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_type = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_type) {
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ return SEPOL_ENOMEM;
+ }
+ memset(new_type, 0, sizeof(type_datum_t));
+
+ new_type->flavor = type->flavor;
+ new_type->flags = type->flags;
+ new_type->s.value = ++state->out->p_types.nprim;
+ if (new_type->s.value > UINT16_MAX) {
+ free(new_id);
+ free(new_type);
+ ERR(state->handle, "type space overflow");
+ return -1;
+ }
+ new_type->primary = 1;
+ state->typemap[type->s.value - 1] = new_type->s.value;
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_type);
+ if (ret) {
+ free(new_id);
+ free(new_type);
+ ERR(state->handle, "hashtab overflow");
+ return -1;
+ }
+
+ if (new_type->flags & TYPE_FLAGS_PERMISSIVE)
+ if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) {
+ ERR(state->handle, "Out of memory!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int attr_convert_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id;
+ type_datum_t *type, *new_type;
+ expand_state_t *state;
+ ebitmap_t tmp_union;
+
+ id = (char *)key;
+ type = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (type->flavor != TYPE_ATTRIB)
+ return 0;
+
+ if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "converting attribute %s", id);
+
+ new_type = hashtab_search(state->out->p_types.table, id);
+ if (!new_type) {
+ ERR(state->handle, "attribute %s vanished!", id);
+ return -1;
+ }
+ if (map_ebitmap(&type->types, &tmp_union, state->typemap)) {
+ ERR(state->handle, "out of memory");
+ return -1;
+ }
+
+ /* then union tmp_union onto &new_type->types */
+ if (ebitmap_union(&new_type->types, &tmp_union)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union);
+
+ return 0;
+}
+
+static int perm_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ symtab_t *s;
+ perm_datum_t *perm, *new_perm;
+
+ id = key;
+ perm = (perm_datum_t *) datum;
+ s = (symtab_t *) data;
+
+ new_perm = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+ if (!new_perm) {
+ return -1;
+ }
+ memset(new_perm, 0, sizeof(perm_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ free(new_perm);
+ return -1;
+ }
+
+ new_perm->s.value = perm->s.value;
+ s->nprim++;
+
+ ret = hashtab_insert(s->table, new_id, (hashtab_datum_t *) new_perm);
+ if (ret) {
+ free(new_id);
+ free(new_perm);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int common_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ common_datum_t *common, *new_common;
+ expand_state_t *state;
+
+ id = (char *)key;
+ common = (common_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (state->verbose)
+ INFO(state->handle, "copying common %s", id);
+
+ new_common = (common_datum_t *) malloc(sizeof(common_datum_t));
+ if (!new_common) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_common, 0, sizeof(common_datum_t));
+ if (symtab_init(&new_common->permissions, PERM_SYMTAB_SIZE)) {
+ ERR(state->handle, "Out of memory!");
+ free(new_common);
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_common);
+ return -1;
+ }
+
+ new_common->s.value = common->s.value;
+ state->out->p_commons.nprim++;
+
+ ret =
+ hashtab_insert(state->out->p_commons.table, new_id,
+ (hashtab_datum_t *) new_common);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_common);
+ free(new_id);
+ return -1;
+ }
+
+ if (hashtab_map
+ (common->permissions.table, perm_copy_callback,
+ &new_common->permissions)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int constraint_node_clone(constraint_node_t ** dst,
+ constraint_node_t * src,
+ expand_state_t * state)
+{
+ constraint_node_t *new_con = NULL, *last_new_con = NULL;
+ constraint_expr_t *new_expr = NULL;
+ *dst = NULL;
+ while (src != NULL) {
+ constraint_expr_t *expr, *expr_l = NULL;
+ new_con =
+ (constraint_node_t *) malloc(sizeof(constraint_node_t));
+ if (!new_con) {
+ goto out_of_mem;
+ }
+ memset(new_con, 0, sizeof(constraint_node_t));
+ new_con->permissions = src->permissions;
+ for (expr = src->expr; expr; expr = expr->next) {
+ if ((new_expr = calloc(1, sizeof(*new_expr))) == NULL) {
+ goto out_of_mem;
+ }
+ if (constraint_expr_init(new_expr) == -1) {
+ goto out_of_mem;
+ }
+ new_expr->expr_type = expr->expr_type;
+ new_expr->attr = expr->attr;
+ new_expr->op = expr->op;
+ if (new_expr->expr_type == CEXPR_NAMES) {
+ if (new_expr->attr & CEXPR_TYPE) {
+ /* Type sets require expansion and conversion. */
+ if (expand_convert_type_set(state->out,
+ state->
+ typemap,
+ expr->
+ type_names,
+ &new_expr->
+ names, 1)) {
+ goto out_of_mem;
+ }
+ } else if (new_expr->attr & CEXPR_ROLE) {
+ if (map_ebitmap(&expr->names, &new_expr->names, state->rolemap)) {
+ goto out_of_mem;
+ }
+ } else if (new_expr->attr & CEXPR_USER) {
+ if (map_ebitmap(&expr->names, &new_expr->names, state->usermap)) {
+ goto out_of_mem;
+ }
+ } else {
+ /* Other kinds of sets do not. */
+ if (ebitmap_cpy(&new_expr->names,
+ &expr->names)) {
+ goto out_of_mem;
+ }
+ }
+ }
+ if (expr_l) {
+ expr_l->next = new_expr;
+ } else {
+ new_con->expr = new_expr;
+ }
+ expr_l = new_expr;
+ new_expr = NULL;
+ }
+ if (last_new_con == NULL) {
+ *dst = new_con;
+ } else {
+ last_new_con->next = new_con;
+ }
+ last_new_con = new_con;
+ src = src->next;
+ }
+
+ return 0;
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ if (new_con)
+ free(new_con);
+ constraint_expr_destroy(new_expr);
+ return -1;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ class_datum_t *class, *new_class;
+ expand_state_t *state;
+
+ id = (char *)key;
+ class = (class_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_CLASSES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying class %s", id);
+
+ new_class = (class_datum_t *) malloc(sizeof(class_datum_t));
+ if (!new_class) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_class, 0, sizeof(class_datum_t));
+ if (symtab_init(&new_class->permissions, PERM_SYMTAB_SIZE)) {
+ ERR(state->handle, "Out of memory!");
+ free(new_class);
+ return -1;
+ }
+
+ new_class->s.value = class->s.value;
+ state->out->p_classes.nprim++;
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_class);
+ return -1;
+ }
+
+ ret =
+ hashtab_insert(state->out->p_classes.table, new_id,
+ (hashtab_datum_t *) new_class);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_class);
+ free(new_id);
+ return -1;
+ }
+
+ if (hashtab_map
+ (class->permissions.table, perm_copy_callback,
+ &new_class->permissions)) {
+ ERR(state->handle, "hashtab overflow");
+ return -1;
+ }
+
+ if (class->comkey) {
+ new_class->comkey = strdup(class->comkey);
+ if (!new_class->comkey) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_class->comdatum =
+ hashtab_search(state->out->p_commons.table,
+ new_class->comkey);
+ if (!new_class->comdatum) {
+ ERR(state->handle, "could not find common datum %s",
+ new_class->comkey);
+ return -1;
+ }
+ new_class->permissions.nprim +=
+ new_class->comdatum->permissions.nprim;
+ }
+
+ return 0;
+}
+
+static int constraint_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id;
+ class_datum_t *class, *new_class;
+ expand_state_t *state;
+
+ id = (char *)key;
+ class = (class_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ new_class = hashtab_search(state->out->p_classes.table, id);
+ if (!new_class) {
+ ERR(state->handle, "class %s vanished", id);
+ return -1;
+ }
+
+ /* constraints */
+ if (constraint_node_clone
+ (&new_class->constraints, class->constraints, state) == -1
+ || constraint_node_clone(&new_class->validatetrans,
+ class->validatetrans, state) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ type_datum_t *type = (type_datum_t *) datum;
+ type_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!type->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_TYPES))
+ return 0;
+
+ bounds_val = state->typemap[type->bounds - 1];
+
+ dest = hashtab_search(state->out->p_types.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "Type lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ role_datum_t *role = (role_datum_t *) datum;
+ role_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!role->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_ROLES))
+ return 0;
+
+ bounds_val = state->rolemap[role->bounds - 1];
+
+ dest = hashtab_search(state->out->p_roles.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "Role lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ user_datum_t *user = (user_datum_t *) datum;
+ user_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!user->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_USERS))
+ return 0;
+
+ bounds_val = state->usermap[user->bounds - 1];
+
+ dest = hashtab_search(state->out->p_users.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "User lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be certain that
+ * the out symbol table will have the type that the alias refers. Otherwise, we
+ * won't be able to find the type value for the alias. We can't depend on the
+ * declaration ordering because of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *alias, *new_alias;
+ expand_state_t *state;
+ uint32_t prival;
+
+ id = (char *)key;
+ alias = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ /* ignore regular types */
+ if (alias->flavor == TYPE_TYPE && alias->primary)
+ return 0;
+
+ /* ignore attributes */
+ if (alias->flavor == TYPE_ATTRIB)
+ return 0;
+
+ if (alias->flavor == TYPE_ALIAS)
+ prival = alias->primary;
+ else
+ prival = alias->s.value;
+
+ if (!is_id_enabled(state->base->p_type_val_to_name[prival - 1],
+ state->base, SYM_TYPES)) {
+ /* The primary type for this alias is not enabled, the alias
+ * shouldn't be either */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying alias %s", id);
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_alias = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_alias) {
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ return SEPOL_ENOMEM;
+ }
+ memset(new_alias, 0, sizeof(type_datum_t));
+ if (alias->flavor == TYPE_TYPE)
+ new_alias->s.value = state->typemap[alias->s.value - 1];
+ else if (alias->flavor == TYPE_ALIAS)
+ new_alias->s.value = state->typemap[alias->primary - 1];
+ else
+ assert(0); /* unreachable */
+
+ new_alias->flags = alias->flags;
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_alias);
+
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_alias);
+ free(new_id);
+ return -1;
+ }
+
+ state->typemap[alias->s.value - 1] = new_alias->s.value;
+
+ if (new_alias->flags & TYPE_FLAGS_PERMISSIVE)
+ if (ebitmap_set_bit(&state->out->permissive_map, new_alias->s.value, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *data)
+{
+ ebitmap_t mapped_roles;
+ role_datum_t *role = (role_datum_t *) datum;
+ expand_state_t *state = (expand_state_t *) data;
+
+ if (map_ebitmap(&role->dominates, &mapped_roles, state->rolemap))
+ return -1;
+
+ ebitmap_destroy(&role->dominates);
+
+ if (ebitmap_cpy(&role->dominates, &mapped_roles))
+ return -1;
+
+ ebitmap_destroy(&mapped_roles);
+
+ return 0;
+}
+
+/* For the role attribute in the base module, escalate its counterpart's
+ * types.types ebitmap in the out module to the counterparts of all the
+ * regular role that belongs to the current role attribute. Note, must be
+ * invoked after role_copy_callback so that state->rolemap is available.
+ */
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id, *base_reg_role_id;
+ role_datum_t *role, *new_role, *regular_role;
+ expand_state_t *state;
+ ebitmap_node_t *rnode;
+ unsigned int i;
+ ebitmap_t mapped_roles;
+
+ id = key;
+ role = (role_datum_t *)datum;
+ state = (expand_state_t *)data;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ if (state->verbose)
+ INFO(state->handle, "fixing role attribute %s", id);
+
+ new_role =
+ (role_datum_t *)hashtab_search(state->out->p_roles.table, id);
+
+ assert(new_role != NULL && new_role->flavor == ROLE_ATTRIB);
+
+ ebitmap_init(&mapped_roles);
+ if (map_ebitmap(&role->roles, &mapped_roles, state->rolemap))
+ return -1;
+ if (ebitmap_union(&new_role->roles, &mapped_roles)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&mapped_roles);
+ return -1;
+ }
+ ebitmap_destroy(&mapped_roles);
+
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ /* take advantage of sym_val_to_name[]
+ * of the base module */
+ base_reg_role_id = state->base->p_role_val_to_name[i];
+ regular_role = (role_datum_t *)hashtab_search(
+ state->out->p_roles.table,
+ base_reg_role_id);
+ assert(regular_role != NULL &&
+ regular_role->flavor == ROLE_ROLE);
+
+ if (ebitmap_union(&regular_role->types.types,
+ &new_role->types.types)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ role_datum_t *role;
+ role_datum_t *new_role;
+ expand_state_t *state;
+ ebitmap_t tmp_union_types;
+
+ id = key;
+ role = (role_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is always value 1 */
+ state->rolemap[role->s.value - 1] = 1;
+ return 0;
+ }
+
+ if (!is_id_enabled(id, state->base, SYM_ROLES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying role %s", id);
+
+ new_role =
+ (role_datum_t *) hashtab_search(state->out->p_roles.table, id);
+ if (!new_role) {
+ new_role = (role_datum_t *) malloc(sizeof(role_datum_t));
+ if (!new_role) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_role, 0, sizeof(role_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ state->out->p_roles.nprim++;
+ new_role->flavor = role->flavor;
+ new_role->s.value = state->out->p_roles.nprim;
+ state->rolemap[role->s.value - 1] = new_role->s.value;
+ ret = hashtab_insert(state->out->p_roles.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_role);
+
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_role);
+ free(new_id);
+ return -1;
+ }
+ }
+
+ /* The dominates bitmap is going to be wrong for the moment,
+ * we'll come back later and remap them, after we are sure all
+ * the roles have been added */
+ if (ebitmap_union(&new_role->dominates, &role->dominates)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ ebitmap_init(&tmp_union_types);
+
+ /* convert types in the role datum in the global symtab */
+ if (expand_convert_type_set
+ (state->out, state->typemap, &role->types, &tmp_union_types, 1)) {
+ ebitmap_destroy(&tmp_union_types);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (ebitmap_union(&new_role->types.types, &tmp_union_types)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union_types);
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union_types);
+
+ return 0;
+}
+
+int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l,
+ policydb_t * p, sepol_handle_t * h)
+{
+ mls_semantic_cat_t *cat;
+ level_datum_t *levdatum;
+ unsigned int i;
+
+ mls_level_init(l);
+
+ if (!p->mls)
+ return 0;
+
+ /* Required not declared. */
+ if (!sl->sens)
+ return 0;
+
+ l->sens = sl->sens;
+ levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+ p->p_sens_val_to_name[l->
+ sens -
+ 1]);
+ for (cat = sl->cat; cat; cat = cat->next) {
+ if (cat->low > cat->high) {
+ ERR(h, "Category range is not valid %s.%s",
+ p->p_cat_val_to_name[cat->low - 1],
+ p->p_cat_val_to_name[cat->high - 1]);
+ return -1;
+ }
+ for (i = cat->low - 1; i < cat->high; i++) {
+ if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+ ERR(h, "Category %s can not be associate with "
+ "level %s",
+ p->p_cat_val_to_name[i],
+ p->p_sens_val_to_name[l->sens - 1]);
+ }
+ if (ebitmap_set_bit(&l->cat, i, 1)) {
+ ERR(h, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int mls_semantic_range_expand(mls_semantic_range_t * sr, mls_range_t * r,
+ policydb_t * p, sepol_handle_t * h)
+{
+ if (mls_semantic_level_expand(&sr->level[0], &r->level[0], p, h) < 0)
+ return -1;
+
+ if (mls_semantic_level_expand(&sr->level[1], &r->level[1], p, h) < 0) {
+ mls_semantic_level_destroy(&sr->level[0]);
+ return -1;
+ }
+
+ if (!mls_level_dom(&r->level[1], &r->level[0])) {
+ mls_range_destroy(r);
+ ERR(h, "MLS range high level does not dominate low level");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ expand_state_t *state;
+ user_datum_t *user;
+ user_datum_t *new_user;
+ char *id, *new_id;
+ ebitmap_t tmp_union;
+
+ id = key;
+ user = (user_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_USERS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying user %s", id);
+
+ new_user =
+ (user_datum_t *) hashtab_search(state->out->p_users.table, id);
+ if (!new_user) {
+ new_user = (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!new_user) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_user, 0, sizeof(user_datum_t));
+
+ state->out->p_users.nprim++;
+ new_user->s.value = state->out->p_users.nprim;
+ state->usermap[user->s.value - 1] = new_user->s.value;
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ret = hashtab_insert(state->out->p_users.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_user);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ user_datum_destroy(new_user);
+ free(new_user);
+ free(new_id);
+ return -1;
+ }
+
+ /* expand the semantic MLS info */
+ if (mls_semantic_range_expand(&user->range,
+ &new_user->exp_range,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (mls_semantic_level_expand(&user->dfltlevel,
+ &new_user->exp_dfltlevel,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (!mls_level_between(&new_user->exp_dfltlevel,
+ &new_user->exp_range.level[0],
+ &new_user->exp_range.level[1])) {
+ ERR(state->handle, "default level not within user "
+ "range");
+ return -1;
+ }
+ } else {
+ /* require that the MLS info match */
+ mls_range_t tmp_range;
+ mls_level_t tmp_level;
+
+ if (mls_semantic_range_expand(&user->range, &tmp_range,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (mls_semantic_level_expand(&user->dfltlevel, &tmp_level,
+ state->out, state->handle)) {
+ mls_range_destroy(&tmp_range);
+ return -1;
+ }
+ if (!mls_range_eq(&new_user->exp_range, &tmp_range) ||
+ !mls_level_eq(&new_user->exp_dfltlevel, &tmp_level)) {
+ mls_range_destroy(&tmp_range);
+ mls_level_destroy(&tmp_level);
+ return -1;
+ }
+ mls_range_destroy(&tmp_range);
+ mls_level_destroy(&tmp_level);
+ }
+
+ ebitmap_init(&tmp_union);
+
+ /* get global roles for this user */
+ if (role_set_expand(&user->roles, &tmp_union, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union);
+ return -1;
+ }
+
+ if (ebitmap_union(&new_user->roles.roles, &tmp_union)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union);
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union);
+
+ return 0;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ expand_state_t *state;
+ cond_bool_datum_t *bool, *new_bool;
+ char *id, *new_id;
+
+ id = key;
+ bool = (cond_bool_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_BOOLS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying boolean %s", id);
+
+ new_bool = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t));
+ if (!new_bool) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_bool);
+ return -1;
+ }
+
+ state->out->p_bools.nprim++;
+ new_bool->s.value = state->out->p_bools.nprim;
+
+ ret = hashtab_insert(state->out->p_bools.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_bool);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_bool);
+ free(new_id);
+ return -1;
+ }
+
+ state->boolmap[bool->s.value - 1] = new_bool->s.value;
+
+ new_bool->state = bool->state;
+
+ return 0;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ level_datum_t *level = (level_datum_t *) datum, *new_level = NULL;
+ char *id = (char *)key, *new_id = NULL;
+
+ if (!is_id_enabled(id, state->base, SYM_LEVELS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying sensitivity level %s", id);
+
+ new_level = (level_datum_t *) malloc(sizeof(level_datum_t));
+ if (!new_level)
+ goto out_of_mem;
+ level_datum_init(new_level);
+ new_level->level = (mls_level_t *) malloc(sizeof(mls_level_t));
+ if (!new_level->level)
+ goto out_of_mem;
+ mls_level_init(new_level->level);
+ new_id = strdup(id);
+ if (!new_id)
+ goto out_of_mem;
+
+ if (mls_level_cpy(new_level->level, level->level)) {
+ goto out_of_mem;
+ }
+ new_level->isalias = level->isalias;
+ state->out->p_levels.nprim++;
+
+ if (hashtab_insert(state->out->p_levels.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_level)) {
+ goto out_of_mem;
+ }
+ return 0;
+
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ if (new_level != NULL && new_level->level != NULL) {
+ mls_level_destroy(new_level->level);
+ free(new_level->level);
+ }
+ level_datum_destroy(new_level);
+ free(new_level);
+ free(new_id);
+ return -1;
+}
+
+static int cats_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ cat_datum_t *cat = (cat_datum_t *) datum, *new_cat = NULL;
+ char *id = (char *)key, *new_id = NULL;
+
+ if (!is_id_enabled(id, state->base, SYM_CATS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying category attribute %s", id);
+
+ new_cat = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+ if (!new_cat)
+ goto out_of_mem;
+ cat_datum_init(new_cat);
+ new_id = strdup(id);
+ if (!new_id)
+ goto out_of_mem;
+
+ new_cat->s.value = cat->s.value;
+ new_cat->isalias = cat->isalias;
+ state->out->p_cats.nprim++;
+ if (hashtab_insert(state->out->p_cats.table,
+ (hashtab_key_t) new_id, (hashtab_datum_t) new_cat)) {
+ goto out_of_mem;
+ }
+
+ return 0;
+
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ cat_datum_destroy(new_cat);
+ free(new_cat);
+ free(new_id);
+ return -1;
+}
+
+static int copy_role_allows(expand_state_t * state, role_allow_rule_t * rules)
+{
+ unsigned int i, j;
+ role_allow_t *cur_allow, *n, *l;
+ role_allow_rule_t *cur;
+ ebitmap_t roles, new_roles;
+ ebitmap_node_t *snode, *tnode;
+
+ /* start at the end of the list */
+ for (l = state->out->role_allow; l && l->next; l = l->next) ;
+
+ cur = rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&new_roles);
+
+ if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ ebitmap_for_each_bit(&roles, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&new_roles, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ /* check for duplicates */
+ cur_allow = state->out->role_allow;
+ while (cur_allow) {
+ if ((cur_allow->role == i + 1) &&
+ (cur_allow->new_role == j + 1))
+ break;
+ cur_allow = cur_allow->next;
+ }
+ if (cur_allow)
+ continue;
+ n = (role_allow_t *)
+ malloc(sizeof(role_allow_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_allow_t));
+ n->role = i + 1;
+ n->new_role = j + 1;
+ if (l) {
+ l->next = n;
+ } else {
+ state->out->role_allow = n;
+ }
+ l = n;
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&new_roles);
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
+{
+ unsigned int i, j, k;
+ role_trans_t *n, *l, *cur_trans;
+ role_trans_rule_t *cur;
+ ebitmap_t roles, types;
+ ebitmap_node_t *rnode, *tnode, *cnode;
+
+ /* start at the end of the list */
+ for (l = state->out->role_tr; l && l->next; l = l->next) ;
+
+ cur = rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&types);
+
+ if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (expand_convert_type_set
+ (state->out, state->typemap, &cur->types, &types, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ebitmap_for_each_bit(&roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
+ continue;
+ ebitmap_for_each_bit(&types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ ebitmap_for_each_bit(&cur->classes, cnode, k) {
+ if (!ebitmap_node_get_bit(cnode, k))
+ continue;
+
+ cur_trans = state->out->role_tr;
+ while (cur_trans) {
+ if ((cur_trans->role ==
+ i + 1) &&
+ (cur_trans->type ==
+ j + 1) &&
+ (cur_trans->tclass ==
+ k + 1)) {
+ if (cur_trans->
+ new_role ==
+ cur->new_role) {
+ break;
+ } else {
+ ERR(state->handle,
+ "Conflicting role trans rule %s %s : %s %s",
+ state->out->p_role_val_to_name[i],
+ state->out->p_type_val_to_name[j],
+ state->out->p_class_val_to_name[k],
+ state->out->p_role_val_to_name[cur->new_role - 1]);
+ return -1;
+ }
+ }
+ cur_trans = cur_trans->next;
+ }
+ if (cur_trans)
+ continue;
+
+ n = (role_trans_t *)
+ malloc(sizeof(role_trans_t));
+ if (!n) {
+ ERR(state->handle,
+ "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_trans_t));
+ n->role = i + 1;
+ n->type = j + 1;
+ n->tclass = k + 1;
+ n->new_role = state->rolemap
+ [cur->new_role - 1];
+ if (l)
+ l->next = n;
+ else
+ state->out->role_tr = n;
+
+ l = n;
+ }
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&types);
+
+ cur = cur->next;
+ }
+ return 0;
+}
+
+static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules)
+{
+ unsigned int i, j;
+ filename_trans_t *new_trans, *tail, *cur_trans;
+ filename_trans_rule_t *cur_rule;
+ ebitmap_t stypes, ttypes;
+ ebitmap_node_t *snode, *tnode;
+
+ /* start at the end of the list */
+ tail = state->out->filename_trans;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ cur_rule = rules;
+ while (cur_rule) {
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set(state->out, state->typemap,
+ &cur_rule->stypes, &stypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (expand_convert_type_set(state->out, state->typemap,
+ &cur_rule->ttypes, &ttypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ ebitmap_for_each_bit(&stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+
+ cur_trans = state->out->filename_trans;
+ while (cur_trans) {
+ if ((cur_trans->stype == i + 1) &&
+ (cur_trans->ttype == j + 1) &&
+ (cur_trans->tclass == cur_rule->tclass) &&
+ (!strcmp(cur_trans->name, cur_rule->name))) {
+ /* duplicate rule, who cares */
+ if (cur_trans->otype == cur_rule->otype)
+ break;
+
+ ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s",
+ cur_trans->name,
+ state->out->p_type_val_to_name[i],
+ state->out->p_type_val_to_name[j],
+ state->out->p_class_val_to_name[cur_trans->tclass - 1],
+ state->out->p_type_val_to_name[cur_trans->otype - 1],
+ state->out->p_type_val_to_name[state->typemap[cur_rule->otype - 1] - 1]);
+
+ return -1;
+ }
+ cur_trans = cur_trans->next;
+ }
+ /* duplicate rule, who cares */
+ if (cur_trans)
+ continue;
+
+ new_trans = malloc(sizeof(*new_trans));
+ if (!new_trans) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_trans, 0, sizeof(*new_trans));
+ if (tail)
+ tail->next = new_trans;
+ else
+ state->out->filename_trans = new_trans;
+ tail = new_trans;
+
+ new_trans->name = strdup(cur_rule->name);
+ if (!new_trans->name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ new_trans->stype = i + 1;
+ new_trans->ttype = j + 1;
+ new_trans->tclass = cur_rule->tclass;
+ new_trans->otype = state->typemap[cur_rule->otype - 1];
+ }
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+
+ cur_rule = cur_rule->next;
+ }
+ return 0;
+}
+
+static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass,
+ mls_semantic_range_t * trange,
+ expand_state_t * state)
+{
+ range_trans_t *rt, *check_rt = state->out->range_tr;
+ mls_range_t exp_range;
+ int rc = -1;
+
+ if (mls_semantic_range_expand(trange, &exp_range, state->out,
+ state->handle))
+ goto out;
+
+ /* check for duplicates/conflicts */
+ while (check_rt) {
+ if ((check_rt->source_type == stype) &&
+ (check_rt->target_type == ttype) &&
+ (check_rt->target_class == tclass)) {
+ if (mls_range_eq(&check_rt->target_range, &exp_range)) {
+ /* duplicate */
+ break;
+ } else {
+ /* conflict */
+ ERR(state->handle,
+ "Conflicting range trans rule %s %s : %s",
+ state->out->p_type_val_to_name[stype - 1],
+ state->out->p_type_val_to_name[ttype - 1],
+ state->out->p_class_val_to_name[tclass -
+ 1]);
+ goto out;
+ }
+ }
+ check_rt = check_rt->next;
+ }
+ if (check_rt) {
+ /* this is a dup - skip */
+ rc = 0;
+ goto out;
+ }
+
+ rt = (range_trans_t *) calloc(1, sizeof(range_trans_t));
+ if (!rt) {
+ ERR(state->handle, "Out of memory!");
+ goto out;
+ }
+
+ rt->next = state->out->range_tr;
+ state->out->range_tr = rt;
+
+ rt->source_type = stype;
+ rt->target_type = ttype;
+ rt->target_class = tclass;
+ if (mls_range_cpy(&rt->target_range, &exp_range)) {
+ ERR(state->handle, "Out of memory!");
+ goto out;
+ }
+
+ rc = 0;
+
+ out:
+ mls_range_destroy(&exp_range);
+ return rc;
+}
+
+static int expand_range_trans(expand_state_t * state,
+ range_trans_rule_t * rules)
+{
+ unsigned int i, j, k;
+ range_trans_rule_t *rule;
+
+ ebitmap_t stypes, ttypes;
+ ebitmap_node_t *snode, *tnode, *cnode;
+
+ if (state->verbose)
+ INFO(state->handle, "expanding range transitions");
+
+ for (rule = rules; rule; rule = rule->next) {
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ /* expand the type sets */
+ if (expand_convert_type_set(state->out, state->typemap,
+ &rule->stypes, &stypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (expand_convert_type_set(state->out, state->typemap,
+ &rule->ttypes, &ttypes, 1)) {
+ ebitmap_destroy(&stypes);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* loop on source type */
+ ebitmap_for_each_bit(&stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ /* loop on target type */
+ ebitmap_for_each_bit(&ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ /* loop on target class */
+ ebitmap_for_each_bit(&rule->tclasses, cnode, k) {
+ if (!ebitmap_node_get_bit(cnode, k))
+ continue;
+
+ if (exp_rangetr_helper(i + 1,
+ j + 1,
+ k + 1,
+ &rule->trange,
+ state)) {
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return -1;
+ }
+ }
+ }
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ }
+
+ return 0;
+}
+
+/* Search for an AV tab node within a hash table with the given key.
+ * If the node does not exist, create it and return it; otherwise
+ * return the pre-existing one.
+*/
+static avtab_ptr_t find_avtab_node(sepol_handle_t * handle,
+ avtab_t * avtab, avtab_key_t * key,
+ cond_av_list_t ** cond)
+{
+ avtab_ptr_t node;
+ avtab_datum_t avdatum;
+ cond_av_list_t *nl;
+
+ node = avtab_search_node(avtab, key);
+
+ /* If this is for conditional policies, keep searching in case
+ the node is part of my conditional avtab. */
+ if (cond) {
+ while (node) {
+ if (node->parse_context == cond)
+ break;
+ node = avtab_search_node_next(node, key->specified);
+ }
+ }
+
+ if (!node) {
+ memset(&avdatum, 0, sizeof avdatum);
+ /* this is used to get the node - insertion is actually unique */
+ node = avtab_insert_nonunique(avtab, key, &avdatum);
+ if (!node) {
+ ERR(handle, "hash table overflow");
+ return NULL;
+ }
+ if (cond) {
+ node->parse_context = cond;
+ nl = (cond_av_list_t *) malloc(sizeof(cond_av_list_t));
+ if (!nl) {
+ ERR(handle, "Memory error");
+ return NULL;
+ }
+ memset(nl, 0, sizeof(cond_av_list_t));
+ nl->node = node;
+ nl->next = *cond;
+ *cond = nl;
+ }
+ }
+
+ return node;
+}
+
+#define EXPAND_RULE_SUCCESS 1
+#define EXPAND_RULE_CONFLICT 0
+#define EXPAND_RULE_ERROR -1
+
+static int expand_terule_helper(sepol_handle_t * handle,
+ policydb_t * p, uint32_t * typemap,
+ uint32_t specified, cond_av_list_t ** cond,
+ cond_av_list_t ** other, uint32_t stype,
+ uint32_t ttype, class_perm_node_t * perms,
+ avtab_t * avtab, int enabled)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ int conflict;
+ uint32_t oldtype = 0, spec = 0;
+
+ if (specified & AVRULE_TRANSITION) {
+ spec = AVTAB_TRANSITION;
+ } else if (specified & AVRULE_MEMBER) {
+ spec = AVTAB_MEMBER;
+ } else if (specified & AVRULE_CHANGE) {
+ spec = AVTAB_CHANGE;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ uint32_t remapped_data =
+ typemap ? typemap[cur->data - 1] : cur->data;
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->class;
+ avkey.specified = spec;
+
+ conflict = 0;
+ /* check to see if the expanded TE already exists --
+ * either in the global scope or in another
+ * conditional AV tab */
+ node = avtab_search_node(&p->te_avtab, &avkey);
+ if (node) {
+ conflict = 1;
+ } else {
+ node = avtab_search_node(&p->te_cond_avtab, &avkey);
+ if (node && node->parse_context != other) {
+ conflict = 2;
+ }
+ }
+
+ if (conflict) {
+ avdatump = &node->datum;
+ if (specified & AVRULE_TRANSITION) {
+ oldtype = avdatump->data;
+ } else if (specified & AVRULE_MEMBER) {
+ oldtype = avdatump->data;
+ } else if (specified & AVRULE_CHANGE) {
+ oldtype = avdatump->data;
+ }
+
+ if (oldtype == remapped_data) {
+ /* if the duplicate is inside the same scope (eg., unconditional
+ * or in same conditional then ignore it */
+ if ((conflict == 1 && cond == NULL)
+ || node->parse_context == cond)
+ return EXPAND_RULE_SUCCESS;
+ ERR(handle, "duplicate TE rule for %s %s:%s %s",
+ p->p_type_val_to_name[avkey.source_type -
+ 1],
+ p->p_type_val_to_name[avkey.target_type -
+ 1],
+ p->p_class_val_to_name[avkey.target_class -
+ 1],
+ p->p_type_val_to_name[oldtype - 1]);
+ return EXPAND_RULE_CONFLICT;
+ }
+ ERR(handle,
+ "conflicting TE rule for (%s, %s:%s): old was %s, new is %s",
+ p->p_type_val_to_name[avkey.source_type - 1],
+ p->p_type_val_to_name[avkey.target_type - 1],
+ p->p_class_val_to_name[avkey.target_class - 1],
+ p->p_type_val_to_name[oldtype - 1],
+ p->p_type_val_to_name[remapped_data - 1]);
+ return EXPAND_RULE_CONFLICT;
+ }
+
+ node = find_avtab_node(handle, avtab, &avkey, cond);
+ if (!node)
+ return -1;
+ if (enabled) {
+ node->key.specified |= AVTAB_ENABLED;
+ } else {
+ node->key.specified &= ~AVTAB_ENABLED;
+ }
+
+ avdatump = &node->datum;
+ if (specified & AVRULE_TRANSITION) {
+ avdatump->data = remapped_data;
+ } else if (specified & AVRULE_MEMBER) {
+ avdatump->data = remapped_data;
+ } else if (specified & AVRULE_CHANGE) {
+ avdatump->data = remapped_data;
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+
+ return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_avrule_helper(sepol_handle_t * handle,
+ uint32_t specified,
+ cond_av_list_t ** cond,
+ uint32_t stype, uint32_t ttype,
+ class_perm_node_t * perms, avtab_t * avtab,
+ int enabled)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ uint32_t spec = 0;
+
+ if (specified & AVRULE_ALLOWED) {
+ spec = AVTAB_ALLOWED;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ spec = AVTAB_AUDITALLOW;
+ } else if (specified & AVRULE_AUDITDENY) {
+ spec = AVTAB_AUDITDENY;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ if (handle && handle->disable_dontaudit)
+ return EXPAND_RULE_SUCCESS;
+ spec = AVTAB_AUDITDENY;
+ } else if (specified & AVRULE_NEVERALLOW) {
+ spec = AVTAB_NEVERALLOW;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->class;
+ avkey.specified = spec;
+
+ node = find_avtab_node(handle, avtab, &avkey, cond);
+ if (!node)
+ return EXPAND_RULE_ERROR;
+ if (enabled) {
+ node->key.specified |= AVTAB_ENABLED;
+ } else {
+ node->key.specified &= ~AVTAB_ENABLED;
+ }
+
+ avdatump = &node->datum;
+ if (specified & AVRULE_ALLOWED) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_NEVERALLOW) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_AUDITDENY) {
+ /* Since a '0' in an auditdeny mask represents
+ * a permission we do NOT want to audit
+ * (dontaudit), we use the '&' operand to
+ * ensure that all '0's in the mask are
+ * retained (much unlike the allow and
+ * auditallow cases).
+ */
+ avdatump->data &= cur->data;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ if (avdatump->data)
+ avdatump->data &= ~cur->data;
+ else
+ avdatump->data = ~cur->data;
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+ return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_rule_helper(sepol_handle_t * handle,
+ policydb_t * p, uint32_t * typemap,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other,
+ int enabled,
+ ebitmap_t * stypes, ebitmap_t * ttypes)
+{
+ unsigned int i, j;
+ int retval;
+ ebitmap_node_t *snode, *tnode;
+
+ ebitmap_for_each_bit(stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ if (source_rule->flags & RULE_SELF) {
+ if (source_rule->specified & AVRULE_AV) {
+ if ((retval =
+ expand_avrule_helper(handle,
+ source_rule->
+ specified, cond, i, i,
+ source_rule->perms,
+ dest_avtab,
+ enabled)) !=
+ EXPAND_RULE_SUCCESS) {
+ return retval;
+ }
+ } else {
+ if ((retval =
+ expand_terule_helper(handle, p,
+ typemap,
+ source_rule->
+ specified, cond,
+ other, i, i,
+ source_rule->perms,
+ dest_avtab,
+ enabled)) !=
+ EXPAND_RULE_SUCCESS) {
+ return retval;
+ }
+ }
+ }
+ ebitmap_for_each_bit(ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ if (source_rule->specified & AVRULE_AV) {
+ if ((retval =
+ expand_avrule_helper(handle,
+ source_rule->
+ specified, cond, i, j,
+ source_rule->perms,
+ dest_avtab,
+ enabled)) !=
+ EXPAND_RULE_SUCCESS) {
+ return retval;
+ }
+ } else {
+ if ((retval =
+ expand_terule_helper(handle, p,
+ typemap,
+ source_rule->
+ specified, cond,
+ other, i, j,
+ source_rule->perms,
+ dest_avtab,
+ enabled)) !=
+ EXPAND_RULE_SUCCESS) {
+ return retval;
+ }
+ }
+ }
+ }
+
+ return EXPAND_RULE_SUCCESS;
+}
+
+/*
+ * Expand a rule into a given avtab - checking for conflicting type
+ * rules in the destination policy. Return EXPAND_RULE_SUCCESS on
+ * success, EXPAND_RULE_CONFLICT if the rule conflicts with something
+ * (and hence was not added), or EXPAND_RULE_ERROR on error.
+ */
+static int convert_and_expand_rule(sepol_handle_t * handle,
+ policydb_t * dest_pol, uint32_t * typemap,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond,
+ cond_av_list_t ** other, int enabled,
+ int do_neverallow)
+{
+ int retval;
+ ebitmap_t stypes, ttypes;
+ unsigned char alwaysexpand;
+
+ if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW)
+ return EXPAND_RULE_SUCCESS;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ /* Force expansion for type rules and for self rules. */
+ alwaysexpand = ((source_rule->specified & AVRULE_TYPE) ||
+ (source_rule->flags & RULE_SELF));
+
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->stypes, &stypes, alwaysexpand))
+ return EXPAND_RULE_ERROR;
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->ttypes, &ttypes, alwaysexpand))
+ return EXPAND_RULE_ERROR;
+
+ retval = expand_rule_helper(handle, dest_pol, typemap,
+ source_rule, dest_avtab,
+ cond, other, enabled, &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+static int cond_avrule_list_copy(policydb_t * dest_pol, avrule_t * source_rules,
+ avtab_t * dest_avtab, cond_av_list_t ** list,
+ cond_av_list_t ** other, uint32_t * typemap,
+ int enabled, expand_state_t * state)
+{
+ avrule_t *cur;
+
+ cur = source_rules;
+ while (cur) {
+ if (convert_and_expand_rule(state->handle, dest_pol,
+ typemap, cur, dest_avtab,
+ list, other, enabled,
+ 0) != EXPAND_RULE_SUCCESS) {
+ return -1;
+ }
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static int cond_node_map_bools(expand_state_t * state, cond_node_t * cn)
+{
+ cond_expr_t *cur;
+ unsigned int i;
+
+ cur = cn->expr;
+ while (cur) {
+ if (cur->bool)
+ cur->bool = state->boolmap[cur->bool - 1];
+ cur = cur->next;
+ }
+
+ for (i = 0; i < min(cn->nbools, COND_MAX_BOOLS); i++)
+ cn->bool_ids[i] = state->boolmap[cn->bool_ids[i] - 1];
+
+ if (cond_normalize_expr(state->out, cn)) {
+ ERR(state->handle, "Error while normalizing conditional");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* copy the nodes in *reverse* order -- the result is that the last
+ * given conditional appears first in the policy, so as to match the
+ * behavior of the upstream compiler */
+static int cond_node_copy(expand_state_t * state, cond_node_t * cn)
+{
+ cond_node_t *new_cond, *tmp;
+
+ if (cn == NULL) {
+ return 0;
+ }
+ if (cond_node_copy(state, cn->next)) {
+ return -1;
+ }
+ if (cond_normalize_expr(state->base, cn)) {
+ ERR(state->handle, "Error while normalizing conditional");
+ return -1;
+ }
+
+ /* create a new temporary conditional node with the booleans
+ * mapped */
+ tmp = cond_node_create(state->base, cn);
+ if (!tmp) {
+ ERR(state->handle, "Out of memory");
+ return -1;
+ }
+
+ if (cond_node_map_bools(state, tmp)) {
+ ERR(state->handle, "Error mapping booleans");
+ return -1;
+ }
+
+ new_cond = cond_node_search(state->out, state->out->cond_list, tmp);
+ if (!new_cond) {
+ cond_node_destroy(tmp);
+ free(tmp);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ cond_node_destroy(tmp);
+ free(tmp);
+
+ if (cond_avrule_list_copy
+ (state->out, cn->avtrue_list, &state->out->te_cond_avtab,
+ &new_cond->true_list, &new_cond->false_list, state->typemap,
+ new_cond->cur_state, state))
+ return -1;
+ if (cond_avrule_list_copy
+ (state->out, cn->avfalse_list, &state->out->te_cond_avtab,
+ &new_cond->false_list, &new_cond->true_list, state->typemap,
+ !new_cond->cur_state, state))
+ return -1;
+
+ return 0;
+}
+
+static int context_copy(context_struct_t * dst, context_struct_t * src,
+ expand_state_t * state)
+{
+ dst->user = state->usermap[src->user - 1];
+ dst->role = state->rolemap[src->role - 1];
+ dst->type = state->typemap[src->type - 1];
+ return mls_context_cpy(dst, src);
+}
+
+static int ocontext_copy_xen(expand_state_t *state)
+{
+ unsigned int i;
+ ocontext_t *c, *n, *l;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ l = NULL;
+ for (c = state->base->ocontexts[i]; c; c = c->next) {
+ n = malloc(sizeof(ocontext_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(ocontext_t));
+ if (l)
+ l->next = n;
+ else
+ state->out->ocontexts[i] = n;
+ l = n;
+ if (context_copy(&n->context[0], &c->context[0],
+ state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ switch (i) {
+ case OCON_XEN_ISID:
+ n->sid[0] = c->sid[0];
+ break;
+ case OCON_XEN_PIRQ:
+ n->u.pirq = c->u.pirq;
+ break;
+ case OCON_XEN_IOPORT:
+ n->u.ioport.low_ioport = c->u.ioport.low_ioport;
+ n->u.ioport.high_ioport =
+ c->u.ioport.high_ioport;
+ break;
+ case OCON_XEN_IOMEM:
+ n->u.iomem.low_iomem = c->u.iomem.low_iomem;
+ n->u.iomem.high_iomem = c->u.iomem.high_iomem;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ n->u.device = c->u.device;
+ break;
+ default:
+ /* shouldn't get here */
+ ERR(state->handle, "Unknown ocontext");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_copy_selinux(expand_state_t *state)
+{
+ unsigned int i, j;
+ ocontext_t *c, *n, *l;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ l = NULL;
+ for (c = state->base->ocontexts[i]; c; c = c->next) {
+ n = malloc(sizeof(ocontext_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(ocontext_t));
+ if (l)
+ l->next = n;
+ else
+ state->out->ocontexts[i] = n;
+ l = n;
+ if (context_copy(&n->context[0], &c->context[0], state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ switch (i) {
+ case OCON_ISID:
+ n->sid[0] = c->sid[0];
+ break;
+ case OCON_FS: /* FALLTHROUGH */
+ case OCON_NETIF:
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (context_copy
+ (&n->context[1], &c->context[1], state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_PORT:
+ n->u.port.protocol = c->u.port.protocol;
+ n->u.port.low_port = c->u.port.low_port;
+ n->u.port.high_port = c->u.port.high_port;
+ break;
+ case OCON_NODE:
+ n->u.node.addr = c->u.node.addr;
+ n->u.node.mask = c->u.node.mask;
+ break;
+ case OCON_FSUSE:
+ n->v.behavior = c->v.behavior;
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_NODE6:
+ for (j = 0; j < 4; j++)
+ n->u.node6.addr[j] = c->u.node6.addr[j];
+ for (j = 0; j < 4; j++)
+ n->u.node6.mask[j] = c->u.node6.mask[j];
+ break;
+ default:
+ /* shouldn't get here */
+ ERR(state->handle, "Unknown ocontext");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_copy(expand_state_t *state, uint32_t target)
+{
+ int rc = -1;
+ switch (target) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_copy_selinux(state);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_copy_xen(state);
+ break;
+ default:
+ ERR(state->handle, "Unknown target");
+ return -1;
+ }
+ return rc;
+}
+
+static int genfs_copy(expand_state_t * state)
+{
+ ocontext_t *c, *newc, *l;
+ genfs_t *genfs, *newgenfs, *end;
+
+ end = NULL;
+ for (genfs = state->base->genfs; genfs; genfs = genfs->next) {
+ newgenfs = malloc(sizeof(genfs_t));
+ if (!newgenfs) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(newgenfs, 0, sizeof(genfs_t));
+ newgenfs->fstype = strdup(genfs->fstype);
+ if (!newgenfs->fstype) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ l = NULL;
+ for (c = genfs->head; c; c = c->next) {
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+ newc->u.name = strdup(c->u.name);
+ if (!newc->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ newc->v.sclass = c->v.sclass;
+ context_copy(&newc->context[0], &c->context[0], state);
+ if (l)
+ l->next = newc;
+ else
+ newgenfs->head = newc;
+ l = newc;
+ }
+ if (!end) {
+ state->out->genfs = newgenfs;
+ } else {
+ end->next = newgenfs;
+ }
+ end = newgenfs;
+ }
+ return 0;
+}
+
+static int type_attr_map(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *ptr)
+{
+ type_datum_t *type;
+ expand_state_t *state = ptr;
+ policydb_t *p = state->out;
+ unsigned int i;
+ ebitmap_node_t *tnode;
+
+ type = (type_datum_t *) datum;
+ if (type->flavor == TYPE_ATTRIB) {
+ if (ebitmap_cpy(&p->attr_type_map[type->s.value - 1],
+ &type->types)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ebitmap_for_each_bit(&type->types, tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ if (ebitmap_set_bit(&p->type_attr_map[i],
+ type->s.value - 1, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy.
+ * this should not be called until after all the blocks have been processed and the attributes in target policy
+ * are complete. */
+int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+ type_set_t * set, ebitmap_t * types,
+ unsigned char alwaysexpand)
+{
+ type_set_t tmpset;
+
+ type_set_init(&tmpset);
+
+ if (map_ebitmap(&set->types, &tmpset.types, typemap))
+ return -1;
+
+ if (map_ebitmap(&set->negset, &tmpset.negset, typemap))
+ return -1;
+
+ tmpset.flags = set->flags;
+
+ if (type_set_expand(&tmpset, types, p, alwaysexpand))
+ return -1;
+
+ type_set_destroy(&tmpset);
+
+ return 0;
+}
+
+/* Expand a rule into a given avtab - checking for conflicting type
+ * rules. Return 1 on success, 0 if the rule conflicts with something
+ * (and hence was not added), or -1 on error. */
+int expand_rule(sepol_handle_t * handle,
+ policydb_t * source_pol,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other, int enabled)
+{
+ int retval;
+ ebitmap_t stypes, ttypes;
+
+ if (source_rule->specified & AVRULE_NEVERALLOW)
+ return 1;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (type_set_expand(&source_rule->stypes, &stypes, source_pol, 1))
+ return -1;
+ if (type_set_expand(&source_rule->ttypes, &ttypes, source_pol, 1))
+ return -1;
+ retval = expand_rule_helper(handle, source_pol, NULL,
+ source_rule, dest_avtab,
+ cond, other, enabled, &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+/* Expand a role set into an ebitmap containing the roles.
+ * This handles the attribute and flags.
+ * Attribute expansion depends on if the rolemap is available.
+ * During module compile the rolemap is not available, the
+ * possible duplicates of a regular role and the role attribute
+ * the regular role belongs to could be properly handled by
+ * copy_role_trans and copy_role_allow.
+ */
+int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap)
+{
+ unsigned int i;
+ ebitmap_node_t *rnode;
+ ebitmap_t mapped_roles, roles;
+ policydb_t *p = out;
+ role_datum_t *role;
+
+ ebitmap_init(r);
+
+ if (x->flags & ROLE_STAR) {
+ for (i = 0; i < p->p_roles.nprim++; i++)
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ return 0;
+ }
+
+ ebitmap_init(&mapped_roles);
+ ebitmap_init(&roles);
+
+ if (rolemap) {
+ assert(base != NULL);
+ ebitmap_for_each_bit(&x->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ /* take advantage of p_role_val_to_struct[]
+ * of the base module */
+ role = base->role_val_to_struct[i];
+ assert(role != NULL);
+ if (role->flavor == ROLE_ATTRIB) {
+ if (ebitmap_union(&roles,
+ &role->roles))
+ goto bad;
+ } else {
+ if (ebitmap_set_bit(&roles, i, 1))
+ goto bad;
+ }
+ }
+ }
+ if (map_ebitmap(&roles, &mapped_roles, rolemap))
+ goto bad;
+ } else {
+ if (ebitmap_cpy(&mapped_roles, &x->roles))
+ goto bad;
+ }
+
+ ebitmap_for_each_bit(&mapped_roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ if (ebitmap_set_bit(r, i, 1))
+ goto bad;
+ }
+ }
+
+ ebitmap_destroy(&mapped_roles);
+ ebitmap_destroy(&roles);
+
+ /* if role is to be complimented, invert the entire bitmap here */
+ if (x->flags & ROLE_COMP) {
+ for (i = 0; i < ebitmap_length(r); i++) {
+ if (ebitmap_get_bit(r, i)) {
+ if (ebitmap_set_bit(r, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ }
+ }
+ }
+ return 0;
+
+bad:
+ ebitmap_destroy(&mapped_roles);
+ ebitmap_destroy(&roles);
+ return -1;
+}
+
+/* Expand a type set into an ebitmap containing the types. This
+ * handles the negset, attributes, and flags.
+ * Attribute expansion depends on several factors:
+ * - if alwaysexpand is 1, then they will be expanded,
+ * - if the type set has a negset or flags, then they will be expanded,
+ * - otherwise, they will not be expanded.
+ */
+int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+ unsigned char alwaysexpand)
+{
+ unsigned int i;
+ ebitmap_t types, neg_types;
+ ebitmap_node_t *tnode;
+
+ ebitmap_init(&types);
+ ebitmap_init(t);
+
+ if (alwaysexpand || ebitmap_length(&set->negset) || set->flags) {
+ /* First go through the types and OR all the attributes to types */
+ ebitmap_for_each_bit(&set->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ if (p->type_val_to_struct[i]->flavor ==
+ TYPE_ATTRIB) {
+ if (ebitmap_union
+ (&types,
+ &p->type_val_to_struct[i]->
+ types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+ } else {
+ /* No expansion of attributes, just copy the set as is. */
+ if (ebitmap_cpy(&types, &set->types))
+ return -1;
+ }
+
+ /* Now do the same thing for negset */
+ ebitmap_init(&neg_types);
+ ebitmap_for_each_bit(&set->negset, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+ if (ebitmap_union
+ (&neg_types,
+ &p->type_val_to_struct[i]->types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&neg_types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ if (set->flags & TYPE_STAR) {
+ /* set all types not in neg_types */
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_get_bit(&neg_types, i))
+ continue;
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB)
+ continue;
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ goto out;
+ }
+
+ ebitmap_for_each_bit(&types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)
+ && (!ebitmap_get_bit(&neg_types, i)))
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+
+ if (set->flags & TYPE_COMP) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+ assert(!ebitmap_get_bit(t, i));
+ continue;
+ }
+ if (ebitmap_get_bit(t, i)) {
+ if (ebitmap_set_bit(t, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ }
+ }
+
+ out:
+
+ ebitmap_destroy(&types);
+ ebitmap_destroy(&neg_types);
+
+ return 0;
+}
+
+static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
+ avrule_t * source_rule)
+{
+ ebitmap_t stypes, ttypes;
+ avrule_t *avrule;
+ class_perm_node_t *cur_perm, *new_perm, *tail_perm;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->stypes, &stypes, 1))
+ return -1;
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->ttypes, &ttypes, 1))
+ return -1;
+
+ avrule = (avrule_t *) malloc(sizeof(avrule_t));
+ if (!avrule)
+ return -1;
+
+ avrule_init(avrule);
+ avrule->specified = AVRULE_NEVERALLOW;
+ avrule->line = source_rule->line;
+ avrule->flags = source_rule->flags;
+
+ if (ebitmap_cpy(&avrule->stypes.types, &stypes))
+ goto err;
+
+ if (ebitmap_cpy(&avrule->ttypes.types, &ttypes))
+ goto err;
+
+ cur_perm = source_rule->perms;
+ tail_perm = NULL;
+ while (cur_perm) {
+ new_perm =
+ (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+ if (!new_perm)
+ goto err;
+ class_perm_node_init(new_perm);
+ new_perm->class = cur_perm->class;
+ assert(new_perm->class);
+
+ /* once we have modules with permissions we'll need to map the permissions (and classes) */
+ new_perm->data = cur_perm->data;
+
+ if (!avrule->perms)
+ avrule->perms = new_perm;
+
+ if (tail_perm)
+ tail_perm->next = new_perm;
+ tail_perm = new_perm;
+ cur_perm = cur_perm->next;
+ }
+
+ /* just prepend the avrule to the first branch; it'll never be
+ written to disk */
+ if (!dest_pol->global->branch_list->avrules)
+ dest_pol->global->branch_list->avrules = avrule;
+ else {
+ avrule->next = dest_pol->global->branch_list->avrules;
+ dest_pol->global->branch_list->avrules = avrule;
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+
+ return 0;
+
+ err:
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ ebitmap_destroy(&avrule->stypes.types);
+ ebitmap_destroy(&avrule->ttypes.types);
+ cur_perm = avrule->perms;
+ while (cur_perm) {
+ tail_perm = cur_perm->next;
+ free(cur_perm);
+ cur_perm = tail_perm;
+ }
+ free(avrule);
+ return -1;
+}
+
+/*
+ * Expands the avrule blocks for a policy. RBAC rules are copied. Neverallow
+ * rules are copied or expanded as per the settings in the state object; all
+ * other AV rules are expanded. If neverallow rules are expanded, they are not
+ * copied, otherwise they are copied for later use by the assertion checker.
+ */
+static int copy_and_expand_avrule_block(expand_state_t * state)
+{
+ avrule_block_t *curblock = state->base->global;
+ avrule_block_t *prevblock;
+ int retval = -1;
+
+ if (avtab_alloc(&state->out->te_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
+ if (avtab_alloc(&state->out->te_cond_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
+ while (curblock) {
+ avrule_decl_t *decl = curblock->enabled;
+ avrule_t *cur_avrule;
+
+ if (decl == NULL) {
+ /* nothing was enabled within this block */
+ goto cont;
+ }
+
+ /* copy role allows and role trans */
+ if (copy_role_allows(state, decl->role_allow_rules) != 0 ||
+ copy_role_trans(state, decl->role_tr_rules) != 0) {
+ goto cleanup;
+ }
+
+ if (expand_filename_trans(state, decl->filename_trans_rules))
+ goto cleanup;
+
+ /* expand the range transition rules */
+ if (expand_range_trans(state, decl->range_tr_rules))
+ goto cleanup;
+
+ /* copy rules */
+ cur_avrule = decl->avrules;
+ while (cur_avrule != NULL) {
+ if (!(state->expand_neverallow)
+ && cur_avrule->specified & AVRULE_NEVERALLOW) {
+ /* copy this over directly so that assertions are checked later */
+ if (copy_neverallow
+ (state->out, state->typemap, cur_avrule))
+ ERR(state->handle,
+ "Error while copying neverallow.");
+ } else {
+ if (cur_avrule->specified & AVRULE_NEVERALLOW) {
+ state->out->unsupported_format = 1;
+ }
+ if (convert_and_expand_rule
+ (state->handle, state->out, state->typemap,
+ cur_avrule, &state->out->te_avtab, NULL,
+ NULL, 0,
+ state->expand_neverallow) !=
+ EXPAND_RULE_SUCCESS) {
+ goto cleanup;
+ }
+ }
+ cur_avrule = cur_avrule->next;
+ }
+
+ /* copy conditional rules */
+ if (cond_node_copy(state, decl->cond_list))
+ goto cleanup;
+
+ cont:
+ prevblock = curblock;
+ curblock = curblock->next;
+
+ if (state->handle && state->handle->expand_consume_base) {
+ /* set base top avrule block in case there
+ * is an error condition and the policy needs
+ * to be destroyed */
+ state->base->global = curblock;
+ avrule_block_destroy(prevblock);
+ }
+ }
+
+ retval = 0;
+
+ cleanup:
+ return retval;
+}
+
+/*
+ * This function allows external users of the library (such as setools) to
+ * expand only the avrules and optionally perform expansion of neverallow rules
+ * or expand into the same policy for analysis purposes.
+ */
+int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+ policydb_t * out, uint32_t * typemap,
+ uint32_t * boolmap, uint32_t * rolemap,
+ uint32_t * usermap, int verbose,
+ int expand_neverallow)
+{
+ expand_state_t state;
+
+ expand_state_init(&state);
+
+ state.base = base;
+ state.out = out;
+ state.typemap = typemap;
+ state.boolmap = boolmap;
+ state.rolemap = rolemap;
+ state.usermap = usermap;
+ state.handle = handle;
+ state.verbose = verbose;
+ state.expand_neverallow = expand_neverallow;
+
+ return copy_and_expand_avrule_block(&state);
+}
+
+/* Linking should always be done before calling expand, even if
+ * there is only a base since all optionals are dealt with at link time
+ * the base passed in should be indexed and avrule blocks should be
+ * enabled.
+ */
+int expand_module(sepol_handle_t * handle,
+ policydb_t * base, policydb_t * out, int verbose, int check)
+{
+ int retval = -1;
+ unsigned int i;
+ expand_state_t state;
+ avrule_block_t *curblock;
+
+ expand_state_init(&state);
+
+ state.verbose = verbose;
+ state.typemap = NULL;
+ state.base = base;
+ state.out = out;
+ state.handle = handle;
+
+ if (base->policy_type != POLICY_BASE) {
+ ERR(handle, "Target of expand was not a base policy.");
+ return -1;
+ }
+
+ state.out->policy_type = POLICY_KERN;
+ state.out->policyvers = POLICYDB_VERSION_MAX;
+
+ /* Copy mls state from base to out */
+ out->mls = base->mls;
+ out->handle_unknown = base->handle_unknown;
+
+ /* Copy target from base to out */
+ out->target_platform = base->target_platform;
+
+ /* Copy policy capabilities */
+ if (ebitmap_cpy(&out->policycaps, &base->policycaps)) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ if ((state.typemap =
+ (uint32_t *) calloc(state.base->p_types.nprim,
+ sizeof(uint32_t))) == NULL) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.boolmap = (uint32_t *)calloc(state.base->p_bools.nprim, sizeof(uint32_t));
+ if (!state.boolmap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.rolemap = (uint32_t *)calloc(state.base->p_roles.nprim, sizeof(uint32_t));
+ if (!state.rolemap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.usermap = (uint32_t *)calloc(state.base->p_users.nprim, sizeof(uint32_t));
+ if (!state.usermap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ /* order is important - types must be first */
+
+ /* copy types */
+ if (hashtab_map(state.base->p_types.table, type_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* convert attribute type sets */
+ if (hashtab_map
+ (state.base->p_types.table, attr_convert_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy commons */
+ if (hashtab_map
+ (state.base->p_commons.table, common_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy classes, note, this does not copy constraints, constraints can't be
+ * copied until after all the blocks have been processed and attributes are complete */
+ if (hashtab_map
+ (state.base->p_classes.table, class_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy type bounds */
+ if (hashtab_map(state.base->p_types.table,
+ type_bounds_copy_callback, &state))
+ goto cleanup;
+
+ /* copy aliases */
+ if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
+ goto cleanup;
+
+ /* index here so that type indexes are available for role_copy_callback */
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* copy roles */
+ if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_roles.table,
+ role_bounds_copy_callback, &state))
+ goto cleanup;
+ /* escalate the type_set_t in a role attribute to all regular roles
+ * that belongs to it. */
+ if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state))
+ goto cleanup;
+
+ /* copy MLS's sensitivity level and categories - this needs to be done
+ * before expanding users (they need to be indexed too) */
+ if (hashtab_map(state.base->p_levels.table, sens_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_cats.table, cats_copy_callback, &state))
+ goto cleanup;
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* copy users */
+ if (hashtab_map(state.base->p_users.table, user_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_users.table,
+ user_bounds_copy_callback, &state))
+ goto cleanup;
+
+ /* copy bools */
+ if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state))
+ goto cleanup;
+
+ if (policydb_index_classes(out)) {
+ ERR(handle, "Error while indexing out classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* loop through all decls and union attributes, roles, users */
+ for (curblock = state.base->global; curblock != NULL;
+ curblock = curblock->next) {
+ avrule_decl_t *decl = curblock->enabled;
+
+ if (decl == NULL) {
+ /* nothing was enabled within this block */
+ continue;
+ }
+
+ /* convert attribute type sets */
+ if (hashtab_map
+ (decl->p_types.table, attr_convert_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy roles */
+ if (hashtab_map
+ (decl->p_roles.table, role_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map
+ (decl->p_roles.table, role_fix_callback, &state))
+ goto cleanup;
+
+ /* copy users */
+ if (hashtab_map
+ (decl->p_users.table, user_copy_callback, &state))
+ goto cleanup;
+
+ }
+
+ /* remap role dominates bitmaps */
+ if (hashtab_map(state.out->p_roles.table, role_remap_dominates, &state)) {
+ goto cleanup;
+ }
+
+ if (copy_and_expand_avrule_block(&state) < 0) {
+ ERR(handle, "Error during expand");
+ goto cleanup;
+ }
+
+ /* copy constraints */
+ if (hashtab_map
+ (state.base->p_classes.table, constraint_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ cond_optimize_lists(state.out->cond_list);
+ evaluate_conds(state.out);
+
+ /* copy ocontexts */
+ if (ocontext_copy(&state, out->target_platform))
+ goto cleanup;
+
+ /* copy genfs */
+ if (genfs_copy(&state))
+ goto cleanup;
+
+ /* Build the type<->attribute maps and remove attributes. */
+ state.out->attr_type_map = malloc(state.out->p_types.nprim *
+ sizeof(ebitmap_t));
+ state.out->type_attr_map = malloc(state.out->p_types.nprim *
+ sizeof(ebitmap_t));
+ if (!state.out->attr_type_map || !state.out->type_attr_map) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+ for (i = 0; i < state.out->p_types.nprim; i++) {
+ ebitmap_init(&state.out->type_attr_map[i]);
+ ebitmap_init(&state.out->attr_type_map[i]);
+ /* add the type itself as the degenerate case */
+ if (ebitmap_set_bit(&state.out->type_attr_map[i], i, 1)) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+ }
+ if (hashtab_map(state.out->p_types.table, type_attr_map, &state))
+ goto cleanup;
+ if (check) {
+ if (hierarchy_check_constraints(handle, state.out))
+ goto cleanup;
+
+ if (check_assertions
+ (handle, state.out,
+ state.out->global->branch_list->avrules))
+ goto cleanup;
+ }
+
+ retval = 0;
+
+ cleanup:
+ free(state.typemap);
+ free(state.boolmap);
+ free(state.rolemap);
+ free(state.usermap);
+ return retval;
+}
+
+static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
+{
+ avtab_ptr_t node;
+ avtab_datum_t *avd;
+ int rc;
+
+ node = avtab_search_node(a, k);
+ if (!node) {
+ rc = avtab_insert(a, k, d);
+ if (rc)
+ ERR(NULL, "Out of memory!");
+ return rc;
+ }
+
+ if ((k->specified & AVTAB_ENABLED) !=
+ (node->key.specified & AVTAB_ENABLED)) {
+ node = avtab_insert_nonunique(a, k, d);
+ if (!node) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ return 0;
+ }
+
+ avd = &node->datum;
+ switch (k->specified & ~AVTAB_ENABLED) {
+ case AVTAB_ALLOWED:
+ case AVTAB_AUDITALLOW:
+ avd->data |= d->data;
+ break;
+ case AVTAB_AUDITDENY:
+ avd->data &= d->data;
+ break;
+ default:
+ ERR(NULL, "Type conflict!");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct expand_avtab_data {
+ avtab_t *expa;
+ policydb_t *p;
+
+};
+
+static int expand_avtab_node(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+ struct expand_avtab_data *ptr = args;
+ avtab_t *expa = ptr->expa;
+ policydb_t *p = ptr->p;
+ type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+ type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+ ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+ ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ avtab_key_t newkey;
+ int rc;
+
+ newkey.target_class = k->target_class;
+ newkey.specified = k->specified;
+
+ if (stype && ttype) {
+ /* Both are individual types, no expansion required. */
+ return expand_avtab_insert(expa, k, d);
+ }
+
+ if (stype) {
+ /* Source is an individual type, target is an attribute. */
+ newkey.source_type = k->source_type;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.target_type = j + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (ttype) {
+ /* Target is an individual type, source is an attribute. */
+ newkey.target_type = k->target_type;
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ newkey.source_type = i + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Both source and target type are attributes. */
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.source_type = i + 1;
+ newkey.target_type = j + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa)
+{
+ struct expand_avtab_data data;
+
+ if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+
+ data.expa = expa;
+ data.p = p;
+ return avtab_map(a, expand_avtab_node, &data);
+}
+
+static int expand_cond_insert(cond_av_list_t ** l,
+ avtab_t * expa,
+ avtab_key_t * k, avtab_datum_t * d)
+{
+ avtab_ptr_t node;
+ avtab_datum_t *avd;
+ cond_av_list_t *nl;
+
+ node = avtab_search_node(expa, k);
+ if (!node ||
+ (k->specified & AVTAB_ENABLED) !=
+ (node->key.specified & AVTAB_ENABLED)) {
+ node = avtab_insert_nonunique(expa, k, d);
+ if (!node) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ node->parse_context = (void *)1;
+ nl = (cond_av_list_t *) malloc(sizeof(*nl));
+ if (!nl) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ memset(nl, 0, sizeof(*nl));
+ nl->node = node;
+ nl->next = *l;
+ *l = nl;
+ return 0;
+ }
+
+ avd = &node->datum;
+ switch (k->specified & ~AVTAB_ENABLED) {
+ case AVTAB_ALLOWED:
+ case AVTAB_AUDITALLOW:
+ avd->data |= d->data;
+ break;
+ case AVTAB_AUDITDENY:
+ avd->data &= d->data;
+ break;
+ default:
+ ERR(NULL, "Type conflict!");
+ return -1;
+ }
+
+ return 0;
+}
+
+int expand_cond_av_node(policydb_t * p,
+ avtab_ptr_t node,
+ cond_av_list_t ** newl, avtab_t * expa)
+{
+ avtab_key_t *k = &node->key;
+ avtab_datum_t *d = &node->datum;
+ type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+ type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+ ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+ ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ avtab_key_t newkey;
+ int rc;
+
+ newkey.target_class = k->target_class;
+ newkey.specified = k->specified;
+
+ if (stype && ttype) {
+ /* Both are individual types, no expansion required. */
+ return expand_cond_insert(newl, expa, k, d);
+ }
+
+ if (stype) {
+ /* Source is an individual type, target is an attribute. */
+ newkey.source_type = k->source_type;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.target_type = j + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (ttype) {
+ /* Target is an individual type, source is an attribute. */
+ newkey.target_type = k->target_type;
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ newkey.source_type = i + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Both source and target type are attributes. */
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.source_type = i + 1;
+ newkey.target_type = j + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+ cond_av_list_t ** newl, avtab_t * expa)
+{
+ cond_av_list_t *cur;
+ avtab_ptr_t node;
+ int rc;
+
+ if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+
+ *newl = NULL;
+ for (cur = l; cur; cur = cur->next) {
+ node = cur->node;
+ rc = expand_cond_av_node(p, node, newl, expa);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/src/genbools.c b/src/genbools.c
new file mode 100644
index 0000000..e353ef3
--- /dev/null
+++ b/src/genbools.c
@@ -0,0 +1,252 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+
+/* -- Deprecated -- */
+
+static char *strtrim(char *dest, char *source, int size)
+{
+ int i = 0;
+ char *ptr = source;
+ i = 0;
+ while (isspace(*ptr) && i < size) {
+ ptr++;
+ i++;
+ }
+ strncpy(dest, ptr, size);
+ for (i = strlen(dest) - 1; i > 0; i--) {
+ if (!isspace(dest[i]))
+ break;
+ }
+ dest[i + 1] = '\0';
+ return dest;
+}
+
+static int process_boolean(char *buffer, char *name, int namesize, int *val)
+{
+ char name1[BUFSIZ];
+ char *ptr;
+ char *tok = strtok_r(buffer, "=", &ptr);
+ if (tok) {
+ strncpy(name1, tok, BUFSIZ - 1);
+ strtrim(name, name1, namesize - 1);
+ if (name[0] == '#')
+ return 0;
+ tok = strtok_r(NULL, "\0", &ptr);
+ if (tok) {
+ while (isspace(*tok))
+ tok++;
+ *val = -1;
+ if (isdigit(tok[0]))
+ *val = atoi(tok);
+ else if (!strncasecmp(tok, "true", sizeof("true") - 1))
+ *val = 1;
+ else if (!strncasecmp
+ (tok, "false", sizeof("false") - 1))
+ *val = 0;
+ if (*val != 0 && *val != 1) {
+ ERR(NULL, "illegal value for boolean "
+ "%s=%s", name, tok);
+ return -1;
+ }
+
+ }
+ }
+ return 1;
+}
+
+static int load_booleans(struct policydb *policydb, const char *path,
+ int *changesp)
+{
+ FILE *boolf;
+ char *buffer = NULL;
+ size_t size = 0;
+ char localbools[BUFSIZ];
+ char name[BUFSIZ];
+ int val;
+ int errors = 0, changes = 0;
+ struct cond_bool_datum *datum;
+
+ boolf = fopen(path, "r");
+ if (boolf == NULL)
+ goto localbool;
+
+ while (getline(&buffer, &size, boolf) > 0) {
+ int ret = process_boolean(buffer, name, sizeof(name), &val);
+ if (ret == -1)
+ errors++;
+ if (ret == 1) {
+ datum = hashtab_search(policydb->p_bools.table, name);
+ if (!datum) {
+ ERR(NULL, "unknown boolean %s", name);
+ errors++;
+ continue;
+ }
+ if (datum->state != val) {
+ datum->state = val;
+ changes++;
+ }
+ }
+ }
+ fclose(boolf);
+ localbool:
+ snprintf(localbools, sizeof(localbools), "%s.local", path);
+ boolf = fopen(localbools, "r");
+ if (boolf != NULL) {
+ while (getline(&buffer, &size, boolf) > 0) {
+ int ret =
+ process_boolean(buffer, name, sizeof(name), &val);
+ if (ret == -1)
+ errors++;
+ if (ret == 1) {
+ datum =
+ hashtab_search(policydb->p_bools.table,
+ name);
+ if (!datum) {
+ ERR(NULL, "unknown boolean %s", name);
+ errors++;
+ continue;
+ }
+ if (datum->state != val) {
+ datum->state = val;
+ changes++;
+ }
+ }
+ }
+ fclose(boolf);
+ }
+ free(buffer);
+ if (errors)
+ errno = EINVAL;
+ *changesp = changes;
+ return errors ? -1 : 0;
+}
+
+int sepol_genbools(void *data, size_t len, char *booleans)
+{
+ struct policydb policydb;
+ struct policy_file pf;
+ int rc, changes = 0;
+
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ if (load_booleans(&policydb, booleans, &changes) < 0) {
+ WARN(NULL, "error while reading %s", booleans);
+ }
+
+ if (!changes)
+ goto out;
+
+ if (evaluate_conds(&policydb) < 0) {
+ ERR(NULL, "error while re-evaluating conditionals");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ rc = policydb_write(&policydb, &pf);
+ if (rc) {
+ ERR(NULL, "unable to write new binary policy image");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ out:
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
+
+int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
+{
+ int rc, changes = 0;
+
+ rc = load_booleans(policydb, booleans, &changes);
+ if (!rc && changes)
+ rc = evaluate_conds(policydb);
+ if (rc)
+ errno = EINVAL;
+ return rc;
+}
+
+/* -- End Deprecated -- */
+
+int sepol_genbools_array(void *data, size_t len, char **names, int *values,
+ int nel)
+{
+ struct policydb policydb;
+ struct policy_file pf;
+ int rc, i, errors = 0;
+ struct cond_bool_datum *datum;
+
+ /* Create policy database from image */
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ for (i = 0; i < nel; i++) {
+ datum = hashtab_search(policydb.p_bools.table, names[i]);
+ if (!datum) {
+ ERR(NULL, "boolean %s no longer in policy", names[i]);
+ errors++;
+ continue;
+ }
+ if (values[i] != 0 && values[i] != 1) {
+ ERR(NULL, "illegal value %d for boolean %s",
+ values[i], names[i]);
+ errors++;
+ continue;
+ }
+ datum->state = values[i];
+ }
+
+ if (evaluate_conds(&policydb) < 0) {
+ ERR(NULL, "error while re-evaluating conditionals");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ rc = policydb_write(&policydb, &pf);
+ if (rc) {
+ ERR(NULL, "unable to write binary policy");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+ if (errors) {
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
diff --git a/src/genusers.c b/src/genusers.c
new file mode 100644
index 0000000..44f94e9
--- /dev/null
+++ b/src/genusers.c
@@ -0,0 +1,318 @@
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sepol/policydb/policydb.h>
+#include <stdarg.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+#include "mls.h"
+
+/* -- Deprecated -- */
+
+void sepol_set_delusers(int on __attribute((unused)))
+{
+ WARN(NULL, "Deprecated interface");
+}
+
+#undef BADLINE
+#define BADLINE() { \
+ ERR(NULL, "invalid entry %s (%s:%u)", \
+ buffer, path, lineno); \
+ continue; \
+}
+
+static int load_users(struct policydb *policydb, const char *path)
+{
+ FILE *fp;
+ char *buffer = NULL, *p, *q, oldc;
+ size_t len = 0;
+ ssize_t nread;
+ unsigned lineno = 0, islist = 0, bit;
+ user_datum_t *usrdatum;
+ role_datum_t *roldatum;
+ ebitmap_node_t *rnode;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ return -1;
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+ while ((nread = getline(&buffer, &len, fp)) > 0) {
+ lineno++;
+ if (buffer[nread - 1] == '\n')
+ buffer[nread - 1] = 0;
+ p = buffer;
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p) || *p == '#')
+ continue;
+
+ if (strncasecmp(p, "user", 4))
+ BADLINE();
+ p += 4;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && !isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ *p++ = 0;
+
+ usrdatum = hashtab_search(policydb->p_users.table, q);
+ if (usrdatum) {
+ /* Replacing an existing user definition. */
+ ebitmap_destroy(&usrdatum->roles.roles);
+ ebitmap_init(&usrdatum->roles.roles);
+ } else {
+ char *id = strdup(q);
+
+ /* Adding a new user definition. */
+ usrdatum =
+ (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!id || !usrdatum) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ memset(usrdatum, 0, sizeof(user_datum_t));
+ usrdatum->s.value = ++policydb->p_users.nprim;
+ ebitmap_init(&usrdatum->roles.roles);
+ if (hashtab_insert(policydb->p_users.table,
+ id, (hashtab_datum_t) usrdatum)) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (strncasecmp(p, "roles", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (*p == '{') {
+ islist = 1;
+ p++;
+ } else
+ islist = 0;
+
+ oldc = 0;
+ do {
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ break;
+
+ q = p;
+ while (*p && *p != ';' && *p != '}' && !isspace(*p))
+ p++;
+ if (!(*p))
+ break;
+ if (*p == '}')
+ islist = 0;
+ oldc = *p;
+ *p++ = 0;
+ if (!q[0])
+ break;
+
+ roldatum = hashtab_search(policydb->p_roles.table, q);
+ if (!roldatum) {
+ ERR(NULL, "undefined role %s (%s:%u)",
+ q, path, lineno);
+ continue;
+ }
+ /* Set the role and every role it dominates */
+ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit))
+ if (ebitmap_set_bit
+ (&usrdatum->roles.roles, bit, 1)) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ }
+ } while (islist);
+ if (oldc == 0)
+ BADLINE();
+
+ if (policydb->mls) {
+ context_struct_t context;
+ char *scontext, *r, *s;
+
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (strncasecmp(p, "level", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && strncasecmp(p, "range", 5))
+ p++;
+ if (!(*p))
+ BADLINE();
+ *--p = 0;
+ p++;
+
+ scontext = malloc(p - q);
+ if (!scontext) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ r = scontext;
+ s = q;
+ while (*s) {
+ if (!isspace(*s))
+ *r++ = *s;
+ s++;
+ }
+ *r = 0;
+ r = scontext;
+
+ context_init(&context);
+ if (mls_context_to_sid(policydb, oldc, &r, &context) <
+ 0) {
+ ERR(NULL, "invalid level %s (%s:%u)", scontext,
+ path, lineno);
+ free(scontext);
+ continue;
+
+ }
+ free(scontext);
+ memcpy(&usrdatum->dfltlevel, &context.range.level[0],
+ sizeof(usrdatum->dfltlevel));
+
+ if (strncasecmp(p, "range", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && *p != ';')
+ p++;
+ if (!(*p))
+ BADLINE();
+ *p++ = 0;
+
+ scontext = malloc(p - q);
+ if (!scontext) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ r = scontext;
+ s = q;
+ while (*s) {
+ if (!isspace(*s))
+ *r++ = *s;
+ s++;
+ }
+ *r = 0;
+ r = scontext;
+
+ context_init(&context);
+ if (mls_context_to_sid(policydb, oldc, &r, &context) <
+ 0) {
+ ERR(NULL, "invalid range %s (%s:%u)", scontext,
+ path, lineno);
+ free(scontext);
+ continue;
+ }
+ free(scontext);
+ memcpy(&usrdatum->range, &context.range,
+ sizeof(usrdatum->range));
+ }
+ }
+
+ free(buffer);
+ fclose(fp);
+ return 0;
+}
+
+int sepol_genusers(void *data, size_t len,
+ const char *usersdir, void **newdata, size_t * newlen)
+{
+ struct policydb policydb;
+ char path[PATH_MAX];
+
+ /* Construct policy database */
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ /* Load locally defined users. */
+ snprintf(path, sizeof path, "%s/local.users", usersdir);
+ if (load_users(&policydb, path) < 0)
+ goto err_destroy;
+
+ /* Write policy database */
+ if (policydb_to_image(NULL, &policydb, newdata, newlen) < 0)
+ goto err_destroy;
+
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
+
+int hidden sepol_genusers_policydb(policydb_t * policydb, const char *usersdir)
+{
+ char path[PATH_MAX];
+
+ /* Load locally defined users. */
+ snprintf(path, sizeof path, "%s/local.users", usersdir);
+ if (load_users(policydb, path) < 0) {
+ ERR(NULL, "unable to load local.users: %s", strerror(errno));
+ return -1;
+ }
+
+ if (policydb_reindex_users(policydb) < 0) {
+ ERR(NULL, "unable to reindex users: %s", strerror(errno));
+ return -1;
+
+ }
+
+ return 0;
+}
+
+/* -- End Deprecated -- */
diff --git a/src/handle.c b/src/handle.c
new file mode 100644
index 0000000..191ac57
--- /dev/null
+++ b/src/handle.c
@@ -0,0 +1,45 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "handle.h"
+#include "debug.h"
+
+sepol_handle_t *sepol_handle_create(void)
+{
+
+ sepol_handle_t *sh = malloc(sizeof(sepol_handle_t));
+ if (sh == NULL)
+ return NULL;
+
+ /* Set callback */
+ sh->msg_callback = sepol_msg_default_handler;
+ sh->msg_callback_arg = NULL;
+
+ /* by default do not disable dontaudits */
+ sh->disable_dontaudit = 0;
+ sh->expand_consume_base = 0;
+
+ return sh;
+}
+
+int sepol_get_disable_dontaudit(sepol_handle_t *sh)
+{
+ assert(sh !=NULL);
+ return sh->disable_dontaudit;
+}
+
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit)
+{
+ assert(sh !=NULL);
+ sh->disable_dontaudit = disable_dontaudit;
+}
+
+void sepol_set_expand_consume_base(sepol_handle_t *sh, int consume_base)
+{
+ assert(sh != NULL);
+ sh->expand_consume_base = consume_base;
+}
+
+void sepol_handle_destroy(sepol_handle_t * sh)
+{
+ free(sh);
+}
diff --git a/src/handle.h b/src/handle.h
new file mode 100644
index 0000000..254fbd8
--- /dev/null
+++ b/src/handle.h
@@ -0,0 +1,23 @@
+#ifndef _SEPOL_INTERNAL_HANDLE_H_
+#define _SEPOL_INTERNAL_HANDLE_H_
+
+#include <sepol/handle.h>
+
+struct sepol_handle {
+ /* Error handling */
+ int msg_level;
+ const char *msg_channel;
+ const char *msg_fname;
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t * handle, const char *fmt, ...);
+ void *msg_callback_arg;
+
+ int disable_dontaudit;
+ int expand_consume_base;
+
+};
+
+#endif
diff --git a/src/hashtab.c b/src/hashtab.c
new file mode 100644
index 0000000..c4be72c
--- /dev/null
+++ b/src/hashtab.c
@@ -0,0 +1,313 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/* FLASK */
+
+/*
+ * Implementation of the hash table type.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+
+hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+ const hashtab_key_t key),
+ int (*keycmp) (hashtab_t h,
+ const hashtab_key_t key1,
+ const hashtab_key_t key2),
+ unsigned int size)
+{
+
+ hashtab_t p;
+ unsigned int i;
+
+ p = (hashtab_t) malloc(sizeof(hashtab_val_t));
+ if (p == NULL)
+ return p;
+
+ memset(p, 0, sizeof(hashtab_val_t));
+ p->size = size;
+ p->nel = 0;
+ p->hash_value = hash_value;
+ p->keycmp = keycmp;
+ p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
+ if (p->htable == NULL) {
+ free(p);
+ return NULL;
+ }
+ for (i = 0; i < size; i++)
+ p->htable[i] = (hashtab_ptr_t) NULL;
+
+ return p;
+}
+
+int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
+{
+ int hvalue;
+ hashtab_ptr_t prev, cur, newnode;
+
+ if (!h)
+ return SEPOL_ENOMEM;
+
+ hvalue = h->hash_value(h, key);
+ prev = NULL;
+ cur = h->htable[hvalue];
+ while (cur && h->keycmp(h, key, cur->key) > 0) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && (h->keycmp(h, key, cur->key) == 0))
+ return SEPOL_EEXIST;
+
+ newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+ if (newnode == NULL)
+ return SEPOL_ENOMEM;
+ memset(newnode, 0, sizeof(struct hashtab_node));
+ newnode->key = key;
+ newnode->datum = datum;
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+
+ h->nel++;
+ return SEPOL_OK;
+}
+
+int hashtab_remove(hashtab_t h, hashtab_key_t key,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ int hvalue;
+ hashtab_ptr_t cur, last;
+
+ if (!h)
+ return SEPOL_ENOENT;
+
+ hvalue = h->hash_value(h, key);
+ last = NULL;
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+ last = cur;
+ cur = cur->next;
+ }
+
+ if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+ return SEPOL_ENOENT;
+
+ if (last == NULL)
+ h->htable[hvalue] = cur->next;
+ else
+ last->next = cur->next;
+
+ if (destroy)
+ destroy(cur->key, cur->datum, args);
+ free(cur);
+ h->nel--;
+ return SEPOL_OK;
+}
+
+int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ int hvalue;
+ hashtab_ptr_t prev, cur, newnode;
+
+ if (!h)
+ return SEPOL_ENOMEM;
+
+ hvalue = h->hash_value(h, key);
+ prev = NULL;
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && (h->keycmp(h, key, cur->key) == 0)) {
+ if (destroy)
+ destroy(cur->key, cur->datum, args);
+ cur->key = key;
+ cur->datum = datum;
+ } else {
+ newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+ if (newnode == NULL)
+ return SEPOL_ENOMEM;
+ memset(newnode, 0, sizeof(struct hashtab_node));
+ newnode->key = key;
+ newnode->datum = datum;
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key)
+{
+
+ int hvalue;
+ hashtab_ptr_t cur;
+
+ if (!h)
+ return NULL;
+
+ hvalue = h->hash_value(h, key);
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+ cur = cur->next;
+
+ if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+ return NULL;
+
+ return cur->datum;
+}
+
+void hashtab_destroy(hashtab_t h)
+{
+ unsigned int i;
+ hashtab_ptr_t cur, temp;
+
+ if (!h)
+ return;
+
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ free(temp);
+ }
+ h->htable[i] = NULL;
+ }
+
+ free(h->htable);
+ h->htable = NULL;
+
+ free(h);
+}
+
+int hashtab_map(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ unsigned int i, ret;
+ hashtab_ptr_t cur;
+
+ if (!h)
+ return SEPOL_OK;
+
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->key, cur->datum, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return SEPOL_OK;
+}
+
+void hashtab_map_remove_on_error(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args)
+{
+ unsigned int i;
+ int ret;
+ hashtab_ptr_t last, cur, temp;
+
+ if (!h)
+ return;
+
+ for (i = 0; i < h->size; i++) {
+ last = NULL;
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->key, cur->datum, args);
+ if (ret) {
+ if (last) {
+ last->next = cur->next;
+ } else {
+ h->htable[i] = cur->next;
+ }
+
+ temp = cur;
+ cur = cur->next;
+ if (destroy)
+ destroy(temp->key, temp->datum, args);
+ free(temp);
+ h->nel--;
+ } else {
+ last = cur;
+ cur = cur->next;
+ }
+ }
+ }
+
+ return;
+}
+
+void hashtab_hash_eval(hashtab_t h, char *tag)
+{
+ unsigned int i;
+ int chain_len, slots_used, max_chain_len;
+ hashtab_ptr_t cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, h->size, max_chain_len);
+}
diff --git a/src/hierarchy.c b/src/hierarchy.c
new file mode 100644
index 0000000..e2df5a4
--- /dev/null
+++ b/src/hierarchy.c
@@ -0,0 +1,501 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Updates: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * adds checks based on newer boundary facility.
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * Copyright (c) 2008 NEC Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+
+typedef struct hierarchy_args {
+ policydb_t *p;
+ avtab_t *expa; /* expanded avtab */
+ /* This tells check_avtab_hierarchy to check this list in addition to the unconditional avtab */
+ cond_av_list_t *opt_cond_list;
+ sepol_handle_t *handle;
+ int numerr;
+} hierarchy_args_t;
+
+/*
+ * find_parent_(type|role|user)
+ *
+ * This function returns the parent datum of given XXX_datum_t
+ * object or NULL, if it doesn't exist.
+ *
+ * If the given datum has a valid bounds, this function merely
+ * returns the indicated object. Otherwise, it looks up the
+ * parent based on the based hierarchy.
+ */
+#define find_parent_template(prefix) \
+int find_parent_##prefix(hierarchy_args_t *a, \
+ prefix##_datum_t *datum, \
+ prefix##_datum_t **parent) \
+{ \
+ char *parent_name, *datum_name, *tmp; \
+ \
+ if (datum->bounds) \
+ *parent = a->p->prefix##_val_to_struct[datum->bounds - 1]; \
+ else { \
+ datum_name = a->p->p_##prefix##_val_to_name[datum->s.value - 1]; \
+ \
+ tmp = strrchr(datum_name, '.'); \
+ /* no '.' means it has no parent */ \
+ if (!tmp) { \
+ *parent = NULL; \
+ return 0; \
+ } \
+ \
+ parent_name = strdup(datum_name); \
+ if (!parent_name) \
+ return -1; \
+ parent_name[tmp - datum_name] = '\0'; \
+ \
+ *parent = hashtab_search(a->p->p_##prefix##s.table, parent_name); \
+ if (!*parent) { \
+ /* Orphan type/role/user */ \
+ ERR(a->handle, \
+ "%s doesn't exist, %s is an orphan", \
+ parent_name, \
+ a->p->p_##prefix##_val_to_name[datum->s.value - 1]); \
+ free(parent_name); \
+ return -1; \
+ } \
+ free(parent_name); \
+ } \
+ \
+ return 0; \
+}
+
+static find_parent_template(type)
+static find_parent_template(role)
+static find_parent_template(user)
+
+static void compute_avtab_datum(hierarchy_args_t *args,
+ avtab_key_t *key,
+ avtab_datum_t *result)
+{
+ avtab_datum_t *avdatp;
+ uint32_t av = 0;
+
+ avdatp = avtab_search(args->expa, key);
+ if (avdatp)
+ av = avdatp->data;
+ if (args->opt_cond_list) {
+ avdatp = cond_av_list_search(key, args->opt_cond_list);
+ if (avdatp)
+ av |= avdatp->data;
+ }
+
+ result->data = av;
+}
+
+/* This function verifies that the type passed in either has a parent or is in the
+ * root of the namespace, 0 on success, 1 on orphan and -1 on error
+ */
+static int check_type_hierarchy_callback(hashtab_key_t k, hashtab_datum_t d,
+ void *args)
+{
+ hierarchy_args_t *a;
+ type_datum_t *t, *tp;
+
+ a = (hierarchy_args_t *) args;
+ t = (type_datum_t *) d;
+
+ if (t->flavor == TYPE_ATTRIB) {
+ /* It's an attribute, we don't care */
+ return 0;
+ }
+ if (find_parent_type(a, t, &tp) < 0)
+ return -1;
+
+ if (tp && tp->flavor == TYPE_ATTRIB) {
+ /* The parent is an attribute but the child isn't, not legal */
+ ERR(a->handle, "type %s is a child of an attribute %s",
+ (char *) k, a->p->p_type_val_to_name[tp->s.value - 1]);
+ a->numerr++;
+ return -1;
+ }
+ return 0;
+}
+
+/* This function only verifies that the avtab node passed in does not violate any
+ * hiearchy constraint via any relationship with other types in the avtab.
+ * it should be called using avtab_map, returns 0 on success, 1 on violation and
+ * -1 on error. opt_cond_list is an optional argument that tells this to check
+ * a conditional list for the relationship as well as the unconditional avtab
+ */
+static int check_avtab_hierarchy_callback(avtab_key_t * k, avtab_datum_t * d,
+ void *args)
+{
+ avtab_key_t key;
+ hierarchy_args_t *a = (hierarchy_args_t *) args;
+ type_datum_t *s, *t1 = NULL, *t2 = NULL;
+ avtab_datum_t av;
+
+ if (!(k->specified & AVTAB_ALLOWED)) {
+ /* This is not an allow rule, no checking done */
+ return 0;
+ }
+
+ /* search for parent first */
+ s = a->p->type_val_to_struct[k->source_type - 1];
+ if (find_parent_type(a, s, &t1) < 0)
+ return -1;
+ if (t1) {
+ /*
+ * search for access allowed between type 1's
+ * parent and type 2.
+ */
+ key.source_type = t1->s.value;
+ key.target_type = k->target_type;
+ key.target_class = k->target_class;
+ key.specified = AVTAB_ALLOWED;
+ compute_avtab_datum(a, &key, &av);
+
+ if ((av.data & d->data) == d->data)
+ return 0;
+ }
+
+ /* next we try type 1 and type 2's parent */
+ s = a->p->type_val_to_struct[k->target_type - 1];
+ if (find_parent_type(a, s, &t2) < 0)
+ return -1;
+ if (t2) {
+ /*
+ * search for access allowed between type 1 and
+ * type 2's parent.
+ */
+ key.source_type = k->source_type;
+ key.target_type = t2->s.value;
+ key.target_class = k->target_class;
+ key.specified = AVTAB_ALLOWED;
+ compute_avtab_datum(a, &key, &av);
+
+ if ((av.data & d->data) == d->data)
+ return 0;
+ }
+
+ if (t1 && t2) {
+ /*
+ * search for access allowed between type 1's parent
+ * and type 2's parent.
+ */
+ key.source_type = t1->s.value;
+ key.target_type = t2->s.value;
+ key.target_class = k->target_class;
+ key.specified = AVTAB_ALLOWED;
+ compute_avtab_datum(a, &key, &av);
+
+ if ((av.data & d->data) == d->data)
+ return 0;
+ }
+
+ /*
+ * Neither one of these types have parents and
+ * therefore the hierarchical constraint does not apply
+ */
+ if (!t1 && !t2)
+ return 0;
+
+ /*
+ * At this point there is a violation of the hierarchal
+ * constraint, send error condition back
+ */
+ ERR(a->handle,
+ "hierarchy violation between types %s and %s : %s { %s }",
+ a->p->p_type_val_to_name[k->source_type - 1],
+ a->p->p_type_val_to_name[k->target_type - 1],
+ a->p->p_class_val_to_name[k->target_class - 1],
+ sepol_av_to_string(a->p, k->target_class, d->data & ~av.data));
+ a->numerr++;
+ return 0;
+}
+
+/*
+ * If same permissions are allowed for same combination of
+ * source and target, we can evaluate them as unconditional
+ * one.
+ * See the following example. A_t type is bounds of B_t type,
+ * so B_t can never have wider permissions then A_t.
+ * A_t has conditional permission on X_t, however, a part of
+ * them (getattr and read) are unconditionaly allowed to A_t.
+ *
+ * Example)
+ * typebounds A_t B_t;
+ *
+ * allow B_t X_t : file { getattr };
+ * if (foo_bool) {
+ * allow A_t X_t : file { getattr read };
+ * } else {
+ * allow A_t X_t : file { getattr read write };
+ * }
+ *
+ * We have to pull up them as unconditional ones in this case,
+ * because it seems to us B_t is violated to bounds constraints
+ * during unconditional policy checking.
+ */
+static int pullup_unconditional_perms(cond_list_t * cond_list,
+ hierarchy_args_t * args)
+{
+ cond_list_t *cur_node;
+ cond_av_list_t *cur_av, *expl_true = NULL, *expl_false = NULL;
+ avtab_t expa_true, expa_false;
+ avtab_datum_t *avdatp;
+ avtab_datum_t avdat;
+ avtab_ptr_t avnode;
+
+ for (cur_node = cond_list; cur_node; cur_node = cur_node->next) {
+ if (avtab_init(&expa_true))
+ goto oom0;
+ if (avtab_init(&expa_false))
+ goto oom1;
+ if (expand_cond_av_list(args->p, cur_node->true_list,
+ &expl_true, &expa_true))
+ goto oom2;
+ if (expand_cond_av_list(args->p, cur_node->false_list,
+ &expl_false, &expa_false))
+ goto oom3;
+ for (cur_av = expl_true; cur_av; cur_av = cur_av->next) {
+ avdatp = avtab_search(&expa_false,
+ &cur_av->node->key);
+ if (!avdatp)
+ continue;
+
+ avdat.data = (cur_av->node->datum.data
+ & avdatp->data);
+ if (!avdat.data)
+ continue;
+
+ avnode = avtab_search_node(args->expa,
+ &cur_av->node->key);
+ if (avnode) {
+ avnode->datum.data |= avdat.data;
+ } else {
+ if (avtab_insert(args->expa,
+ &cur_av->node->key,
+ &avdat))
+ goto oom4;
+ }
+ }
+ cond_av_list_destroy(expl_false);
+ cond_av_list_destroy(expl_true);
+ avtab_destroy(&expa_false);
+ avtab_destroy(&expa_true);
+ }
+ return 0;
+
+oom4:
+ cond_av_list_destroy(expl_false);
+oom3:
+ cond_av_list_destroy(expl_true);
+oom2:
+ avtab_destroy(&expa_false);
+oom1:
+ avtab_destroy(&expa_true);
+oom0:
+ ERR(args->handle, "out of memory on conditional av list expansion");
+ return 1;
+}
+
+static int check_cond_avtab_hierarchy(cond_list_t * cond_list,
+ hierarchy_args_t * args)
+{
+ int rc;
+ cond_list_t *cur_node;
+ cond_av_list_t *cur_av, *expl = NULL;
+ avtab_t expa;
+ hierarchy_args_t *a = (hierarchy_args_t *) args;
+ avtab_datum_t avdat, *uncond;
+
+ for (cur_node = cond_list; cur_node; cur_node = cur_node->next) {
+ /*
+ * Check true condition
+ */
+ if (avtab_init(&expa))
+ goto oom;
+ if (expand_cond_av_list(args->p, cur_node->true_list,
+ &expl, &expa)) {
+ avtab_destroy(&expa);
+ goto oom;
+ }
+ args->opt_cond_list = expl;
+ for (cur_av = expl; cur_av; cur_av = cur_av->next) {
+ avdat.data = cur_av->node->datum.data;
+ uncond = avtab_search(a->expa, &cur_av->node->key);
+ if (uncond)
+ avdat.data |= uncond->data;
+ rc = check_avtab_hierarchy_callback(&cur_av->node->key,
+ &avdat, args);
+ if (rc)
+ args->numerr++;
+ }
+ cond_av_list_destroy(expl);
+
+ /*
+ * Check false condition
+ */
+ if (avtab_init(&expa))
+ goto oom;
+ if (expand_cond_av_list(args->p, cur_node->false_list,
+ &expl, &expa)) {
+ avtab_destroy(&expa);
+ goto oom;
+ }
+ args->opt_cond_list = expl;
+ for (cur_av = expl; cur_av; cur_av = cur_av->next) {
+ avdat.data = cur_av->node->datum.data;
+ uncond = avtab_search(a->expa, &cur_av->node->key);
+ if (uncond)
+ avdat.data |= uncond->data;
+
+ rc = check_avtab_hierarchy_callback(&cur_av->node->key,
+ &avdat, args);
+ if (rc)
+ a->numerr++;
+ }
+ cond_av_list_destroy(expl);
+ avtab_destroy(&expa);
+ }
+
+ return 0;
+
+ oom:
+ ERR(args->handle, "out of memory on conditional av list expansion");
+ return 1;
+}
+
+/* The role hierarchy is defined as: a child role cannot have more types than it's parent.
+ * This function should be called with hashtab_map, it will return 0 on success, 1 on
+ * constraint violation and -1 on error
+ */
+static int check_role_hierarchy_callback(hashtab_key_t k
+ __attribute__ ((unused)),
+ hashtab_datum_t d, void *args)
+{
+ hierarchy_args_t *a;
+ role_datum_t *r, *rp;
+
+ a = (hierarchy_args_t *) args;
+ r = (role_datum_t *) d;
+
+ if (find_parent_role(a, r, &rp) < 0)
+ return -1;
+
+ if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
+ /* hierarchical constraint violation, return error */
+ ERR(a->handle, "Role hierarchy violation, %s exceeds %s",
+ (char *) k, a->p->p_role_val_to_name[rp->s.value - 1]);
+ a->numerr++;
+ }
+ return 0;
+}
+
+/* The user hierarchy is defined as: a child user cannot have a role that
+ * its parent doesn't have. This function should be called with hashtab_map,
+ * it will return 0 on success, 1 on constraint violation and -1 on error.
+ */
+static int check_user_hierarchy_callback(hashtab_key_t k
+ __attribute__ ((unused)),
+ hashtab_datum_t d, void *args)
+{
+ hierarchy_args_t *a;
+ user_datum_t *u, *up;
+
+ a = (hierarchy_args_t *) args;
+ u = (user_datum_t *) d;
+
+ if (find_parent_user(a, u, &up) < 0)
+ return -1;
+
+ if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
+ /* hierarchical constraint violation, return error */
+ ERR(a->handle, "User hierarchy violation, %s exceeds %s",
+ (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
+ a->numerr++;
+ }
+ return 0;
+}
+
+int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
+{
+ hierarchy_args_t args;
+ avtab_t expa;
+
+ if (avtab_init(&expa))
+ goto oom;
+ if (expand_avtab(p, &p->te_avtab, &expa)) {
+ avtab_destroy(&expa);
+ goto oom;
+ }
+
+ args.p = p;
+ args.expa = &expa;
+ args.opt_cond_list = NULL;
+ args.handle = handle;
+ args.numerr = 0;
+
+ if (hashtab_map(p->p_types.table, check_type_hierarchy_callback, &args))
+ goto bad;
+
+ if (pullup_unconditional_perms(p->cond_list, &args))
+ return -1;
+
+ if (avtab_map(&expa, check_avtab_hierarchy_callback, &args))
+ goto bad;
+
+ if (check_cond_avtab_hierarchy(p->cond_list, &args))
+ goto bad;
+
+ if (hashtab_map(p->p_roles.table, check_role_hierarchy_callback, &args))
+ goto bad;
+
+ if (hashtab_map(p->p_users.table, check_user_hierarchy_callback, &args))
+ goto bad;
+
+ if (args.numerr) {
+ ERR(handle, "%d total errors found during hierarchy check",
+ args.numerr);
+ goto bad;
+ }
+
+ avtab_destroy(&expa);
+ return 0;
+
+ bad:
+ avtab_destroy(&expa);
+ return -1;
+
+ oom:
+ ERR(handle, "Out of memory");
+ return -1;
+}
diff --git a/src/iface_internal.h b/src/iface_internal.h
new file mode 100644
index 0000000..5b78d9b
--- /dev/null
+++ b/src/iface_internal.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_IFACE_INTERNAL_H_
+#define _SEPOL_IFACE_INTERNAL_H_
+
+#include <sepol/iface_record.h>
+#include <sepol/interfaces.h>
+#include "dso.h"
+
+hidden_proto(sepol_iface_create)
+ hidden_proto(sepol_iface_free)
+ hidden_proto(sepol_iface_get_ifcon)
+ hidden_proto(sepol_iface_get_msgcon)
+ hidden_proto(sepol_iface_get_name)
+ hidden_proto(sepol_iface_key_create)
+ hidden_proto(sepol_iface_key_unpack)
+ hidden_proto(sepol_iface_set_ifcon)
+ hidden_proto(sepol_iface_set_msgcon)
+ hidden_proto(sepol_iface_set_name)
+#endif
diff --git a/src/iface_record.c b/src/iface_record.c
new file mode 100644
index 0000000..09adeb7
--- /dev/null
+++ b/src/iface_record.c
@@ -0,0 +1,233 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "iface_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_iface {
+
+ /* Interface name */
+ char *name;
+
+ /* Interface context */
+ sepol_context_t *netif_con;
+
+ /* Message context */
+ sepol_context_t *netmsg_con;
+};
+
+struct sepol_iface_key {
+
+ /* Interface name */
+ const char *name;
+};
+
+/* Key */
+int sepol_iface_key_create(sepol_handle_t * handle,
+ const char *name, sepol_iface_key_t ** key_ptr)
+{
+
+ sepol_iface_key_t *tmp_key =
+ (sepol_iface_key_t *) malloc(sizeof(sepol_iface_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, could not create interface key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_key_create)
+
+void sepol_iface_key_unpack(const sepol_iface_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_iface_key_unpack)
+
+int sepol_iface_key_extract(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_key_t ** key_ptr)
+{
+
+ if (sepol_iface_key_create(handle, iface->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from "
+ "interface %s", iface->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_iface_key_free(sepol_iface_key_t * key)
+{
+ free(key);
+}
+
+int sepol_iface_compare(const sepol_iface_t * iface,
+ const sepol_iface_key_t * key)
+{
+
+ return strcmp(iface->name, key->name);
+}
+
+int sepol_iface_compare2(const sepol_iface_t * iface,
+ const sepol_iface_t * iface2)
+{
+
+ return strcmp(iface->name, iface2->name);
+}
+
+/* Create */
+int sepol_iface_create(sepol_handle_t * handle, sepol_iface_t ** iface)
+{
+
+ sepol_iface_t *tmp_iface =
+ (sepol_iface_t *) malloc(sizeof(sepol_iface_t));
+
+ if (!tmp_iface) {
+ ERR(handle, "out of memory, could not create "
+ "interface record");
+ return STATUS_ERR;
+ }
+
+ tmp_iface->name = NULL;
+ tmp_iface->netif_con = NULL;
+ tmp_iface->netmsg_con = NULL;
+ *iface = tmp_iface;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_create)
+
+/* Name */
+const char *sepol_iface_get_name(const sepol_iface_t * iface)
+{
+
+ return iface->name;
+}
+
+hidden_def(sepol_iface_get_name)
+
+int sepol_iface_set_name(sepol_handle_t * handle,
+ sepol_iface_t * iface, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, " "could not set interface name");
+ return STATUS_ERR;
+ }
+ free(iface->name);
+ iface->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_name)
+
+/* Interface Context */
+sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface)
+{
+
+ return iface->netif_con;
+}
+
+hidden_def(sepol_iface_get_ifcon)
+
+int sepol_iface_set_ifcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set interface context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(iface->netif_con);
+ iface->netif_con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_ifcon)
+
+/* Message Context */
+sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface)
+{
+
+ return iface->netmsg_con;
+}
+
+hidden_def(sepol_iface_get_msgcon)
+
+int sepol_iface_set_msgcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set message context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(iface->netmsg_con);
+ iface->netmsg_con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_msgcon)
+
+/* Deep copy clone */
+int sepol_iface_clone(sepol_handle_t * handle,
+ const sepol_iface_t * iface, sepol_iface_t ** iface_ptr)
+{
+
+ sepol_iface_t *new_iface = NULL;
+ if (sepol_iface_create(handle, &new_iface) < 0)
+ goto err;
+
+ if (sepol_iface_set_name(handle, new_iface, iface->name) < 0)
+ goto err;
+
+ if (iface->netif_con &&
+ (sepol_context_clone
+ (handle, iface->netif_con, &new_iface->netif_con) < 0))
+ goto err;
+
+ if (iface->netmsg_con &&
+ (sepol_context_clone
+ (handle, iface->netmsg_con, &new_iface->netmsg_con) < 0))
+ goto err;
+
+ *iface_ptr = new_iface;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone interface record");
+ sepol_iface_free(new_iface);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_iface_free(sepol_iface_t * iface)
+{
+
+ if (!iface)
+ return;
+
+ free(iface->name);
+ sepol_context_free(iface->netif_con);
+ sepol_context_free(iface->netmsg_con);
+ free(iface);
+}
+
+hidden_def(sepol_iface_free)
diff --git a/src/interfaces.c b/src/interfaces.c
new file mode 100644
index 0000000..b82d0f3
--- /dev/null
+++ b/src/interfaces.c
@@ -0,0 +1,273 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/interfaces.h>
+#include "iface_internal.h"
+
+/* Create a low level structure from record */
+static int iface_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** iface, const sepol_iface_t * record)
+{
+
+ ocontext_t *tmp_iface = NULL;
+ context_struct_t *tmp_con = NULL;
+
+ tmp_iface = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_iface)
+ goto omem;
+
+ /* Name */
+ tmp_iface->u.name = strdup(sepol_iface_get_name(record));
+ if (!tmp_iface->u.name)
+ goto omem;
+
+ /* Interface Context */
+ if (context_from_record(handle, policydb,
+ &tmp_con, sepol_iface_get_ifcon(record)) < 0)
+ goto err;
+ context_cpy(&tmp_iface->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ /* Message Context */
+ if (context_from_record(handle, policydb,
+ &tmp_con, sepol_iface_get_msgcon(record)) < 0)
+ goto err;
+ context_cpy(&tmp_iface->context[1], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *iface = tmp_iface;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_iface != NULL) {
+ free(tmp_iface->u.name);
+ context_destroy(&tmp_iface->context[0]);
+ context_destroy(&tmp_iface->context[1]);
+ free(tmp_iface);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ ERR(handle, "error creating interface structure");
+ return STATUS_ERR;
+}
+
+static int iface_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * iface, sepol_iface_t ** record)
+{
+
+ char *name = iface->u.name;
+ context_struct_t *ifcon = &iface->context[0];
+ context_struct_t *msgcon = &iface->context[1];
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_iface_t *tmp_record = NULL;
+
+ if (sepol_iface_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_iface_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ if (context_to_record(handle, policydb, ifcon, &tmp_con) < 0)
+ goto err;
+ if (sepol_iface_set_ifcon(handle, tmp_record, tmp_con) < 0)
+ goto err;
+ sepol_context_free(tmp_con);
+ tmp_con = NULL;
+
+ if (context_to_record(handle, policydb, msgcon, &tmp_con) < 0)
+ goto err;
+ if (sepol_iface_set_msgcon(handle, tmp_record, tmp_con) < 0)
+ goto err;
+ sepol_context_free(tmp_con);
+ tmp_con = NULL;
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert interface %s to record", name);
+ sepol_context_free(tmp_con);
+ sepol_iface_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Check if an interface exists */
+int sepol_iface_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p,
+ const sepol_iface_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ *response = 0;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+/* Query an interface */
+int sepol_iface_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_iface_key_t * key, sepol_iface_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+
+ if (iface_to_record(handle, policydb, c, response) < 0)
+ goto err;
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query interface %s", name);
+ return STATUS_ERR;
+}
+
+/* Load an interface into policy */
+int sepol_iface_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_iface_key_t * key,
+ const sepol_iface_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *head, *prev, *c, *iface = NULL;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ if (iface_from_record(handle, policydb, &iface, data) < 0)
+ goto err;
+
+ prev = NULL;
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+
+ /* Replace */
+ iface->next = c->next;
+ if (prev == NULL)
+ policydb->ocontexts[OCON_NETIF] = iface;
+ else
+ prev->next = iface;
+ free(c->u.name);
+ context_destroy(&c->context[0]);
+ context_destroy(&c->context[1]);
+ free(c);
+
+ return STATUS_SUCCESS;
+ }
+ prev = c;
+ }
+
+ /* Attach to context list */
+ iface->next = policydb->ocontexts[OCON_NETIF];
+ policydb->ocontexts[OCON_NETIF] = iface;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "error while loading interface %s", name);
+
+ if (iface != NULL) {
+ free(iface->u.name);
+ context_destroy(&iface->context[0]);
+ context_destroy(&iface->context[1]);
+ free(iface);
+ }
+ return STATUS_ERR;
+}
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+int sepol_iface_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_iface_t * iface,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_iface_t *iface = NULL;
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ int status;
+
+ if (iface_to_record(handle, policydb, c, &iface) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(iface, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_iface_free(iface);
+ iface = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over interfaces");
+ sepol_iface_free(iface);
+ return STATUS_ERR;
+}
diff --git a/src/libsepol.map b/src/libsepol.map
new file mode 100644
index 0000000..719e5b7
--- /dev/null
+++ b/src/libsepol.map
@@ -0,0 +1,19 @@
+{
+ global:
+ sepol_module_package_*; sepol_link_modules; sepol_expand_module; sepol_link_packages;
+ sepol_bool_*; sepol_genbools*;
+ sepol_context_*; sepol_mls_*; sepol_check_context;
+ sepol_iface_*;
+ sepol_port_*;
+ sepol_node_*;
+ sepol_user_*; sepol_genusers; sepol_set_delusers;
+ sepol_msg_*; sepol_debug;
+ sepol_handle_*;
+ sepol_policydb_*; sepol_set_policydb_from_file;
+ sepol_policy_kern_*;
+ sepol_policy_file_*;
+ sepol_get_disable_dontaudit;
+ sepol_set_disable_dontaudit;
+ sepol_set_expand_consume_base;
+ local: *;
+};
diff --git a/src/libsepol.pc.in b/src/libsepol.pc.in
new file mode 100644
index 0000000..e52f589
--- /dev/null
+++ b/src/libsepol.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@libdir@
+includedir=@includedir@
+
+Name: libsepol
+Description: SELinux policy library
+Version: @VERSION@
+URL: http://userspace.selinuxproject.org/
+Libs: -L${libdir} -lsepol
+Cflags: -I${includedir}
diff --git a/src/link.c b/src/link.c
new file mode 100644
index 0000000..421c47b
--- /dev/null
+++ b/src/link.c
@@ -0,0 +1,2598 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/util.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+typedef struct policy_module {
+ policydb_t *policy;
+ uint32_t num_decls;
+ uint32_t *map[SYM_NUM];
+ uint32_t *avdecl_map;
+ uint32_t **perm_map;
+ uint32_t *perm_map_len;
+
+ /* a pointer to within the base module's avrule_block chain to
+ * where this module's global now resides */
+ avrule_block_t *base_global;
+} policy_module_t;
+
+typedef struct link_state {
+ int verbose;
+ policydb_t *base;
+ avrule_block_t *last_avrule_block, *last_base_avrule_block;
+ uint32_t next_decl_id, current_decl_id;
+
+ /* temporary variables, used during hashtab_map() calls */
+ policy_module_t *cur;
+ char *cur_mod_name;
+ avrule_decl_t *dest_decl;
+ class_datum_t *src_class, *dest_class;
+ char *dest_class_name;
+ char dest_class_req; /* flag indicating the class was not declared */
+ uint32_t symbol_num;
+ /* used to report the name of the module if dependancy error occurs */
+ policydb_t **decl_to_mod;
+
+ /* error reporting fields */
+ sepol_handle_t *handle;
+} link_state_t;
+
+typedef struct missing_requirement {
+ uint32_t symbol_type;
+ uint32_t symbol_value;
+ uint32_t perm_value;
+} missing_requirement_t;
+
+static const char *symtab_names[SYM_NUM] = {
+ "common", "class", "role", "type/attribute", "user",
+ "bool", "level", "category"
+};
+
+/* Deallocates all elements within a module, but NOT the policydb_t
+ * structure within, as well as the pointer itself. */
+static void policy_module_destroy(policy_module_t * mod)
+{
+ unsigned int i;
+ if (mod == NULL) {
+ return;
+ }
+ for (i = 0; i < SYM_NUM; i++) {
+ free(mod->map[i]);
+ }
+ for (i = 0; mod->perm_map != NULL && i < mod->policy->p_classes.nprim;
+ i++) {
+ free(mod->perm_map[i]);
+ }
+ free(mod->perm_map);
+ free(mod->perm_map_len);
+ free(mod->avdecl_map);
+ free(mod);
+}
+
+/***** functions that copy identifiers from a module to base *****/
+
+/* Note: there is currently no scoping for permissions, which causes some
+ * strange side-effects. The current approach is this:
+ *
+ * a) perm is required and the class _and_ perm are declared in base: only add a mapping.
+ * b) perm is required and the class and perm are _not_ declared in base: simply add the permissions
+ * to the object class. This means that the requirements for the decl are the union of the permissions
+ * required for all decls, but who cares.
+ * c) perm is required, the class is declared in base, but the perm is not present. Nothing we can do
+ * here because we can't mark a single permission as required, so we bail with a requirement error
+ * _even_ if we are in an optional.
+ *
+ * A is correct behavior, b is wrong but not too bad, c is totall wrong for optionals. Fixing this requires
+ * a format change.
+ */
+static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *perm_id = key, *new_id = NULL;
+ perm_datum_t *perm, *new_perm = NULL, *dest_perm;
+ link_state_t *state = (link_state_t *) data;
+
+ class_datum_t *src_class = state->src_class;
+ class_datum_t *dest_class = state->dest_class;
+ policy_module_t *mod = state->cur;
+ uint32_t sclassi = src_class->s.value - 1;
+ int ret;
+
+ perm = (perm_datum_t *) datum;
+ dest_perm = hashtab_search(dest_class->permissions.table, perm_id);
+ if (dest_perm == NULL && dest_class->comdatum != NULL) {
+ dest_perm =
+ hashtab_search(dest_class->comdatum->permissions.table,
+ perm_id);
+ }
+
+ if (dest_perm == NULL) {
+ /* If the object class was not declared in the base, add the perm
+ * to the object class. */
+ if (state->dest_class_req) {
+ /* If the class was required (not declared), insert the new permission */
+ new_id = strdup(perm_id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Memory error");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ new_perm =
+ (perm_datum_t *) calloc(1, sizeof(perm_datum_t));
+ if (new_perm == NULL) {
+ ERR(state->handle, "Memory error");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ ret = hashtab_insert(dest_class->permissions.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_perm);
+ if (ret) {
+ ERR(state->handle,
+ "could not insert permission into class\n");
+ goto err;
+ }
+ new_perm->s.value = dest_class->permissions.nprim + 1;
+ dest_perm = new_perm;
+ } else {
+ /* this is case c from above */
+ ERR(state->handle,
+ "Module %s depends on permission %s in class %s, not satisfied",
+ state->cur_mod_name, perm_id,
+ state->dest_class_name);
+ return SEPOL_EREQ;
+ }
+ }
+
+ /* build the mapping for permissions encompassing this class.
+ * unlike symbols, the permission map translates between
+ * module permission bit to target permission bit. that bit
+ * may have originated from the class -or- it could be from
+ * the class's common parent.*/
+ if (perm->s.value > mod->perm_map_len[sclassi]) {
+ uint32_t *newmap = calloc(perm->s.value, sizeof(*newmap));
+ if (newmap == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memcpy(newmap, mod->perm_map[sclassi],
+ mod->perm_map_len[sclassi] * sizeof(*newmap));
+ free(mod->perm_map[sclassi]);
+ mod->perm_map[sclassi] = newmap;
+ mod->perm_map_len[sclassi] = perm->s.value;
+ }
+ mod->perm_map[sclassi][perm->s.value - 1] = dest_perm->s.value;
+
+ return 0;
+ err:
+ free(new_id);
+ free(new_perm);
+ return ret;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key, *new_id = NULL;
+ class_datum_t *cladatum, *new_class = NULL;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope = NULL;
+ int ret;
+
+ cladatum = (class_datum_t *) datum;
+ state->dest_class_req = 0;
+
+ new_class = hashtab_search(state->base->p_classes.table, id);
+ /* If there is not an object class already in the base symtab that means
+ * that either a) a module is trying to declare a new object class (which
+ * the compiler should prevent) or b) an object class was required that is
+ * not in the base.
+ */
+ if (new_class == NULL) {
+ scope =
+ hashtab_search(state->cur->policy->p_classes_scope.table,
+ id);
+ if (scope == NULL) {
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not yet declare new classes.",
+ state->cur_mod_name);
+ ret = SEPOL_ENOTSUP;
+ goto err;
+ } else {
+ /* It would be nice to error early here because the requirement is
+ * not met, but we cannot because the decl might be optional (in which
+ * case we should record the requirement so that it is just turned
+ * off). Note: this will break horribly if modules can declare object
+ * classes because the class numbers will be all wrong (i.e., they
+ * might be assigned in the order they were required rather than the
+ * current scheme which ensures correct numbering by ordering the
+ * declarations properly). This can't be fixed until some infrastructure
+ * for querying the object class numbers is in place. */
+ state->dest_class_req = 1;
+ new_class =
+ (class_datum_t *) calloc(1, sizeof(class_datum_t));
+ if (new_class == NULL) {
+ ERR(state->handle, "Memory error\n");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ if (symtab_init
+ (&new_class->permissions, PERM_SYMTAB_SIZE)) {
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ new_id = strdup(id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Memory error\n");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ ret = hashtab_insert(state->base->p_classes.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_class);
+ if (ret) {
+ ERR(state->handle,
+ "could not insert new class into symtab");
+ goto err;
+ }
+ new_class->s.value = ++(state->base->p_classes.nprim);
+ }
+ }
+
+ state->cur->map[SYM_CLASSES][cladatum->s.value - 1] =
+ new_class->s.value;
+
+ /* copy permissions */
+ state->src_class = cladatum;
+ state->dest_class = new_class;
+ state->dest_class_name = (char *)key;
+
+ ret =
+ hashtab_map(cladatum->permissions.table, permission_copy_callback,
+ state);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+ err:
+ free(new_class);
+ free(new_id);
+ return ret;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ role_datum_t *role, *base_role, *new_role = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ role = (role_datum_t *) datum;
+
+ base_role = hashtab_search(state->base->p_roles.table, id);
+ if (base_role != NULL) {
+ /* role already exists. check that it is what this
+ * module expected. duplicate declarations (e.g., two
+ * modules both declare role foo_r) is checked during
+ * scope_copy_callback(). */
+ if (role->flavor == ROLE_ATTRIB
+ && base_role->flavor != ROLE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a role attribute, but it was already declared as a regular role.",
+ state->cur_mod_name, id);
+ return -1;
+ } else if (role->flavor != ROLE_ATTRIB
+ && base_role->flavor == ROLE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a regular role, but it was already declared as a role attribute.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+ } else {
+ if (state->verbose)
+ INFO(state->handle, "copying role %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_role =
+ (role_datum_t *) malloc(sizeof(*new_role))) == NULL) {
+ goto cleanup;
+ }
+ role_datum_init(new_role);
+
+ /* new_role's dominates, types and roles field will be copied
+ * during role_fix_callback() */
+ new_role->flavor = role->flavor;
+ new_role->s.value = state->base->p_roles.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_roles.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_role);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_roles.nprim++;
+ base_role = new_role;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_role = malloc(sizeof(*new_role))) == NULL) {
+ goto cleanup;
+ }
+ role_datum_init(new_role);
+ new_role->flavor = base_role->flavor;
+ new_role->s.value = base_role->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_roles.table, new_id, new_role)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_roles.nprim++;
+ }
+
+ state->cur->map[SYM_ROLES][role->s.value - 1] = base_role->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_datum_destroy(new_role);
+ free(new_id);
+ free(new_role);
+ return -1;
+}
+
+/* Copy types and attributes from a module into the base module. The
+ * attributes are copied, but the types that make up this attribute
+ * are delayed type_fix_callback(). */
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ type_datum_t *type, *base_type, *new_type = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ type = (type_datum_t *) datum;
+ if ((type->flavor == TYPE_TYPE && !type->primary)
+ || type->flavor == TYPE_ALIAS) {
+ /* aliases are handled later, in alias_copy_callback() */
+ return 0;
+ }
+
+ base_type = hashtab_search(state->base->p_types.table, id);
+ if (base_type != NULL) {
+ /* type already exists. check that it is what this
+ * module expected. duplicate declarations (e.g., two
+ * modules both declare type foo_t) is checked during
+ * scope_copy_callback(). */
+ if (type->flavor == TYPE_ATTRIB
+ && base_type->flavor != TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be an attribute, but it was already declared as a type.",
+ state->cur_mod_name, id);
+ return -1;
+ } else if (type->flavor != TYPE_ATTRIB
+ && base_type->flavor == TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a type, but it was already declared as an attribute.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+ /* permissive should pass to the base type */
+ base_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+ } else {
+ if (state->verbose)
+ INFO(state->handle, "copying type %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_type =
+ (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ new_type->primary = type->primary;
+ new_type->flags = type->flags;
+ new_type->flavor = type->flavor;
+ /* for attributes, the writing of new_type->types is
+ done in type_fix_callback() */
+
+ new_type->s.value = state->base->p_types.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_type);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_types.nprim++;
+ base_type = new_type;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_type = calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ new_type->primary = type->primary;
+ new_type->flavor = type->flavor;
+ new_type->flags = type->flags;
+ new_type->s.value = base_type->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_types.table, new_id, new_type)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_types.nprim++;
+ }
+
+ state->cur->map[SYM_TYPES][type->s.value - 1] = base_type->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ free(new_type);
+ return -1;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ user_datum_t *user, *base_user, *new_user = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ user = (user_datum_t *) datum;
+
+ base_user = hashtab_search(state->base->p_users.table, id);
+ if (base_user == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying user %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_user =
+ (user_datum_t *) malloc(sizeof(*new_user))) == NULL) {
+ goto cleanup;
+ }
+ user_datum_init(new_user);
+ /* new_users's roles and MLS fields will be copied during
+ user_fix_callback(). */
+
+ new_user->s.value = state->base->p_users.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_users.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_user);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_users.nprim++;
+ base_user = new_user;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_user = malloc(sizeof(*new_user))) == NULL) {
+ goto cleanup;
+ }
+ user_datum_init(new_user);
+ new_user->s.value = base_user->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_users.table, new_id, new_user)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_users.nprim++;
+ }
+
+ state->cur->map[SYM_USERS][user->s.value - 1] = base_user->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ user_datum_destroy(new_user);
+ free(new_id);
+ free(new_user);
+ return -1;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ cond_bool_datum_t *booldatum, *base_bool, *new_bool = NULL;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ booldatum = (cond_bool_datum_t *) datum;
+
+ base_bool = hashtab_search(state->base->p_bools.table, id);
+ if (base_bool == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying boolean %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_bool =
+ (cond_bool_datum_t *) malloc(sizeof(*new_bool))) == NULL) {
+ goto cleanup;
+ }
+ new_bool->s.value = state->base->p_bools.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_bools.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_bool);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_bools.nprim++;
+ base_bool = new_bool;
+
+ }
+
+ /* Get the scope info for this boolean to see if this is the declaration,
+ * if so set the state */
+ scope = hashtab_search(state->cur->policy->p_bools_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL)
+ base_bool->state = booldatum->state;
+
+ state->cur->map[SYM_BOOLS][booldatum->s.value - 1] = base_bool->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ cond_destroy_bool(new_id, new_bool, NULL);
+ return -1;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ level_datum_t *level, *base_level;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ level = (level_datum_t *) datum;
+
+ base_level = hashtab_search(state->base->p_levels.table, id);
+ if (!base_level) {
+ scope =
+ hashtab_search(state->cur->policy->p_sens_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not declare new sensitivities.",
+ state->cur_mod_name);
+ return SEPOL_ENOTSUP;
+ }
+ if (scope->scope == SCOPE_REQ) {
+ /* unmet requirement */
+ ERR(state->handle,
+ "%s: Sensitivity %s not declared by base.",
+ state->cur_mod_name, id);
+ return SEPOL_ENOTSUP;
+ }
+ }
+
+ state->cur->map[SYM_LEVELS][level->level->sens - 1] =
+ base_level->level->sens;
+
+ return 0;
+}
+
+static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ cat_datum_t *cat, *base_cat;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ cat = (cat_datum_t *) datum;
+
+ base_cat = hashtab_search(state->base->p_cats.table, id);
+ if (!base_cat) {
+ scope =
+ hashtab_search(state->cur->policy->p_cat_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not declare new categories.",
+ state->cur_mod_name);
+ return SEPOL_ENOTSUP;
+ }
+ if (scope->scope == SCOPE_REQ) {
+ /* unmet requirement */
+ ERR(state->handle,
+ "%s: Category %s not declared by base.",
+ state->cur_mod_name, id);
+ return SEPOL_ENOTSUP;
+ }
+ }
+
+ state->cur->map[SYM_CATS][cat->s.value - 1] = base_cat->s.value;
+
+ return 0;
+}
+
+static int (*copy_callback_f[SYM_NUM]) (hashtab_key_t key,
+ hashtab_datum_t datum, void *datap) = {
+NULL, class_copy_callback, role_copy_callback, type_copy_callback,
+ user_copy_callback, bool_copy_callback, sens_copy_callback,
+ cat_copy_callback};
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ type_datum_t *type = (type_datum_t *) datum;
+ type_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!type->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_TYPES][type->bounds - 1];
+
+ dest = hashtab_search(state->base->p_types.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "Type lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ role_datum_t *role = (role_datum_t *) datum;
+ role_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!role->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_ROLES][role->bounds - 1];
+
+ dest = hashtab_search(state->base->p_roles.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "Role lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ user_datum_t *user = (user_datum_t *) datum;
+ user_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!user->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_USERS][user->bounds - 1];
+
+ dest = hashtab_search(state->base->p_users.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "User lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be
+ * certain that the base symbol table will have the type that the
+ * alias refers. Otherwise, we won't be able to find the type value
+ * for the alias. We can't depend on the declaration ordering because
+ * of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key, *new_id = NULL, *target_id;
+ type_datum_t *type, *base_type, *new_type = NULL, *target_type;
+ link_state_t *state = (link_state_t *) data;
+ policy_module_t *mod = state->cur;
+ int primval;
+
+ type = (type_datum_t *) datum;
+ /* there are 2 kinds of aliases. Ones with their own value (TYPE_ALIAS)
+ * and ones with the value of their primary (TYPE_TYPE && type->primary = 0)
+ */
+ if (!
+ (type->flavor == TYPE_ALIAS
+ || (type->flavor == TYPE_TYPE && !type->primary))) {
+ /* ignore types and attributes -- they were handled in
+ * type_copy_callback() */
+ return 0;
+ }
+
+ if (type->flavor == TYPE_ALIAS)
+ primval = type->primary;
+ else
+ primval = type->s.value;
+
+ target_id = mod->policy->p_type_val_to_name[primval - 1];
+ target_type = hashtab_search(state->base->p_types.table, target_id);
+ if (target_type == NULL) {
+ ERR(state->handle, "%s: Could not find type %s for alias %s.",
+ state->cur_mod_name, target_id, id);
+ return -1;
+ }
+
+ if (!strcmp(id, target_id)) {
+ ERR(state->handle, "%s: Self aliasing of %s.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+
+ target_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+
+ base_type = hashtab_search(state->base->p_types.table, id);
+ if (base_type == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying alias %s", id);
+
+ if ((new_type =
+ (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ /* the linked copy always has TYPE_ALIAS style aliases */
+ new_type->primary = target_type->s.value;
+ new_type->flags = target_type->flags;
+ new_type->flavor = TYPE_ALIAS;
+ new_type->s.value = state->base->p_types.nprim + 1;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->base->p_types.table, new_id, new_type)) {
+ goto cleanup;
+ }
+ state->base->p_types.nprim++;
+ base_type = new_type;
+ } else {
+
+ /* if this already exists and isn't an alias it was required by another module (or base)
+ * and inserted into the hashtable as a type, fix it up now */
+
+ if (base_type->flavor == TYPE_ALIAS) {
+ /* error checking */
+ assert(base_type->primary == target_type->s.value);
+ assert(base_type->primary ==
+ mod->map[SYM_TYPES][primval - 1]);
+ assert(mod->map[SYM_TYPES][type->s.value - 1] ==
+ base_type->primary);
+ return 0;
+ }
+
+ if (base_type->flavor == TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s is an alias of an attribute, not allowed", id);
+ return -1;
+ }
+
+ base_type->flavor = TYPE_ALIAS;
+ base_type->primary = target_type->s.value;
+ base_type->flags |= (target_type->flags & TYPE_FLAGS_PERMISSIVE);
+
+ }
+ /* the aliases map points from its value to its primary so when this module
+ * references this type the value it gets back from the map is the primary */
+ mod->map[SYM_TYPES][type->s.value - 1] = base_type->primary;
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ free(new_type);
+ return -1;
+}
+
+/*********** callbacks that fix bitmaps ***********/
+
+static int type_set_convert(type_set_t * types, type_set_t * dst,
+ policy_module_t * mod, link_state_t * state
+ __attribute__ ((unused)))
+{
+ unsigned int i;
+ ebitmap_node_t *tnode;
+ ebitmap_for_each_bit(&types->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&dst->types, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ ebitmap_for_each_bit(&types->negset, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&dst->negset, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ dst->flags = types->flags;
+ return 0;
+
+ cleanup:
+ return -1;
+}
+
+/* OR 2 typemaps together and at the same time map the src types to
+ * the correct values in the dst typeset.
+ */
+static int type_set_or_convert(type_set_t * types, type_set_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ type_set_t ts_tmp;
+
+ type_set_init(&ts_tmp);
+ if (type_set_convert(types, &ts_tmp, mod, state) == -1) {
+ goto cleanup;
+ }
+ if (type_set_or_eq(dst, &ts_tmp)) {
+ goto cleanup;
+ }
+ type_set_destroy(&ts_tmp);
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ type_set_destroy(&ts_tmp);
+ return -1;
+}
+
+static int role_set_or_convert(role_set_t * roles, role_set_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ unsigned int i;
+ ebitmap_t tmp;
+ ebitmap_node_t *rnode;
+
+ ebitmap_init(&tmp);
+ ebitmap_for_each_bit(&roles->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dst->roles, &tmp)) {
+ goto cleanup;
+ }
+ dst->flags |= roles->flags;
+ ebitmap_destroy(&tmp);
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp);
+ return -1;
+}
+
+static int mls_level_convert(mls_semantic_level_t * src, mls_semantic_level_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ mls_semantic_cat_t *src_cat, *new_cat;
+
+ if (!mod->policy->mls)
+ return 0;
+
+ /* Required not declared. */
+ if (!src->sens)
+ return 0;
+
+ assert(mod->map[SYM_LEVELS][src->sens - 1]);
+ dst->sens = mod->map[SYM_LEVELS][src->sens - 1];
+
+ for (src_cat = src->cat; src_cat; src_cat = src_cat->next) {
+ new_cat =
+ (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!new_cat) {
+ ERR(state->handle, "Out of memory");
+ return -1;
+ }
+ mls_semantic_cat_init(new_cat);
+
+ new_cat->next = dst->cat;
+ dst->cat = new_cat;
+
+ assert(mod->map[SYM_CATS][src_cat->low - 1]);
+ dst->cat->low = mod->map[SYM_CATS][src_cat->low - 1];
+ assert(mod->map[SYM_CATS][src_cat->high - 1]);
+ dst->cat->high = mod->map[SYM_CATS][src_cat->high - 1];
+ }
+
+ return 0;
+}
+
+static int mls_range_convert(mls_semantic_range_t * src, mls_semantic_range_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ int ret;
+ ret = mls_level_convert(&src->level[0], &dst->level[0], mod, state);
+ if (ret)
+ return ret;
+ ret = mls_level_convert(&src->level[1], &dst->level[1], mod, state);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ char *id = key;
+ role_datum_t *role, *dest_role = NULL;
+ link_state_t *state = (link_state_t *) data;
+ ebitmap_t e_tmp;
+ policy_module_t *mod = state->cur;
+ ebitmap_node_t *rnode;
+ hashtab_t role_tab;
+
+ role = (role_datum_t *) datum;
+ if (state->dest_decl == NULL)
+ role_tab = state->base->p_roles.table;
+ else
+ role_tab = state->dest_decl->p_roles.table;
+
+ dest_role = hashtab_search(role_tab, id);
+ assert(dest_role != NULL);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing role %s", id);
+ }
+
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&role->dominates, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dest_role->dominates, &e_tmp)) {
+ goto cleanup;
+ }
+ if (type_set_or_convert(&role->types, &dest_role->types, mod, state)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+
+ if (role->flavor == ROLE_ATTRIB) {
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dest_role->roles, &e_tmp)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+ }
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&e_tmp);
+ return -1;
+}
+
+static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ char *id = key;
+ type_datum_t *type, *new_type = NULL;
+ link_state_t *state = (link_state_t *) data;
+ ebitmap_t e_tmp;
+ policy_module_t *mod = state->cur;
+ ebitmap_node_t *tnode;
+ symtab_t *typetab;
+
+ type = (type_datum_t *) datum;
+
+ if (state->dest_decl == NULL)
+ typetab = &state->base->p_types;
+ else
+ typetab = &state->dest_decl->p_types;
+
+ /* only fix attributes */
+ if (type->flavor != TYPE_ATTRIB) {
+ return 0;
+ }
+
+ new_type = hashtab_search(typetab->table, id);
+ assert(new_type != NULL && new_type->flavor == TYPE_ATTRIB);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing attribute %s", id);
+ }
+
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&type->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&new_type->types, &e_tmp)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&e_tmp);
+ return -1;
+}
+
+static int user_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ user_datum_t *user, *new_user = NULL;
+ link_state_t *state = (link_state_t *) data;
+ policy_module_t *mod = state->cur;
+ symtab_t *usertab;
+
+ user = (user_datum_t *) datum;
+
+ if (state->dest_decl == NULL)
+ usertab = &state->base->p_users;
+ else
+ usertab = &state->dest_decl->p_users;
+
+ new_user = hashtab_search(usertab->table, id);
+ assert(new_user != NULL);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing user %s", id);
+ }
+
+ if (role_set_or_convert(&user->roles, &new_user->roles, mod, state)) {
+ goto cleanup;
+ }
+
+ if (mls_range_convert(&user->range, &new_user->range, mod, state))
+ goto cleanup;
+
+ if (mls_level_convert(&user->dfltlevel, &new_user->dfltlevel, mod, state))
+ goto cleanup;
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int (*fix_callback_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+NULL, NULL, role_fix_callback, type_fix_callback, user_fix_callback,
+ NULL, NULL, NULL};
+
+/*********** functions that copy AV rules ***********/
+
+static int copy_avrule_list(avrule_t * list, avrule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned int i;
+ avrule_t *cur, *new_rule = NULL, *tail;
+ class_perm_node_t *cur_perm, *new_perm, *tail_perm = NULL;
+
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+
+ cur = list;
+ while (cur) {
+ if ((new_rule = (avrule_t *) malloc(sizeof(avrule_t))) == NULL) {
+ goto cleanup;
+ }
+ avrule_init(new_rule);
+
+ new_rule->specified = cur->specified;
+ new_rule->flags = cur->flags;
+ if (type_set_convert
+ (&cur->stypes, &new_rule->stypes, module, state) == -1
+ || type_set_convert(&cur->ttypes, &new_rule->ttypes, module,
+ state) == -1) {
+ goto cleanup;
+ }
+
+ cur_perm = cur->perms;
+ tail_perm = NULL;
+ while (cur_perm) {
+ if ((new_perm = (class_perm_node_t *)
+ malloc(sizeof(class_perm_node_t))) == NULL) {
+ goto cleanup;
+ }
+ class_perm_node_init(new_perm);
+
+ new_perm->class =
+ module->map[SYM_CLASSES][cur_perm->class - 1];
+ assert(new_perm->class);
+
+ if (new_rule->specified & AVRULE_AV) {
+ for (i = 0;
+ i <
+ module->perm_map_len[cur_perm->class - 1];
+ i++) {
+ if (!(cur_perm->data & (1U << i)))
+ continue;
+ new_perm->data |=
+ (1U <<
+ (module->
+ perm_map[cur_perm->class - 1][i] -
+ 1));
+ }
+ } else {
+ new_perm->data =
+ module->map[SYM_TYPES][cur_perm->data - 1];
+ }
+
+ if (new_rule->perms == NULL) {
+ new_rule->perms = new_perm;
+ } else {
+ tail_perm->next = new_perm;
+ }
+ tail_perm = new_perm;
+ cur_perm = cur_perm->next;
+ }
+ new_rule->line = cur->line;
+
+ cur = cur->next;
+
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ }
+
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ avrule_destroy(new_rule);
+ free(new_rule);
+ return -1;
+}
+
+static int copy_role_trans_list(role_trans_rule_t * list,
+ role_trans_rule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ role_trans_rule_t *cur, *new_rule = NULL, *tail;
+ unsigned int i;
+ ebitmap_node_t *cnode;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ while (cur) {
+ if ((new_rule =
+ (role_trans_rule_t *) malloc(sizeof(role_trans_rule_t))) ==
+ NULL) {
+ goto cleanup;
+ }
+ role_trans_rule_init(new_rule);
+
+ if (role_set_or_convert
+ (&cur->roles, &new_rule->roles, module, state)
+ || type_set_or_convert(&cur->types, &new_rule->types,
+ module, state)) {
+ goto cleanup;
+ }
+
+ ebitmap_for_each_bit(&cur->classes, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ assert(module->map[SYM_CLASSES][i]);
+ if (ebitmap_set_bit(&new_rule->classes,
+ module->
+ map[SYM_CLASSES][i] - 1,
+ 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ new_rule->new_role = module->map[SYM_ROLES][cur->new_role - 1];
+
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_trans_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_role_allow_list(role_allow_rule_t * list,
+ role_allow_rule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ role_allow_rule_t *cur, *new_rule = NULL, *tail;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+
+ while (cur) {
+ if ((new_rule =
+ (role_allow_rule_t *) malloc(sizeof(role_allow_rule_t))) ==
+ NULL) {
+ goto cleanup;
+ }
+ role_allow_rule_init(new_rule);
+
+ if (role_set_or_convert
+ (&cur->roles, &new_rule->roles, module, state)
+ || role_set_or_convert(&cur->new_roles,
+ &new_rule->new_roles, module,
+ state)) {
+ goto cleanup;
+ }
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_allow_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_filename_trans_list(filename_trans_rule_t * list,
+ filename_trans_rule_t ** dst,
+ policy_module_t * module,
+ link_state_t * state)
+{
+ filename_trans_rule_t *cur, *new_rule, *tail;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ while (cur) {
+ new_rule = malloc(sizeof(*new_rule));
+ if (!new_rule)
+ goto err;
+
+ filename_trans_rule_init(new_rule);
+
+ if (*dst == NULL)
+ *dst = new_rule;
+ else
+ tail->next = new_rule;
+ tail = new_rule;
+
+ new_rule->name = strdup(cur->name);
+ if (!new_rule->name)
+ goto err;
+
+ if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module, state) ||
+ type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module, state))
+ goto err;
+
+ new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1];
+ new_rule->otype = module->map[SYM_TYPES][cur->otype - 1];
+
+ cur = cur->next;
+ }
+ return 0;
+err:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int copy_range_trans_list(range_trans_rule_t * rules,
+ range_trans_rule_t ** dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ range_trans_rule_t *rule, *new_rule = NULL;
+ unsigned int i;
+ ebitmap_node_t *cnode;
+
+ for (rule = rules; rule; rule = rule->next) {
+ new_rule =
+ (range_trans_rule_t *) malloc(sizeof(range_trans_rule_t));
+ if (!new_rule)
+ goto cleanup;
+
+ range_trans_rule_init(new_rule);
+
+ new_rule->next = *dst;
+ *dst = new_rule;
+
+ if (type_set_convert(&rule->stypes, &new_rule->stypes,
+ mod, state))
+ goto cleanup;
+
+ if (type_set_convert(&rule->ttypes, &new_rule->ttypes,
+ mod, state))
+ goto cleanup;
+
+ ebitmap_for_each_bit(&rule->tclasses, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ assert(mod->map[SYM_CLASSES][i]);
+ if (ebitmap_set_bit
+ (&new_rule->tclasses,
+ mod->map[SYM_CLASSES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ if (mls_range_convert(&rule->trange, &new_rule->trange, mod, state))
+ goto cleanup;
+ }
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ range_trans_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_cond_list(cond_node_t * list, cond_node_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned i;
+ cond_node_t *cur, *new_node = NULL, *tail;
+ cond_expr_t *cur_expr;
+ tail = *dst;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ cur = list;
+ while (cur) {
+ new_node = (cond_node_t *) malloc(sizeof(cond_node_t));
+ if (!new_node) {
+ goto cleanup;
+ }
+ memset(new_node, 0, sizeof(cond_node_t));
+
+ new_node->cur_state = cur->cur_state;
+ new_node->expr = cond_copy_expr(cur->expr);
+ if (!new_node->expr)
+ goto cleanup;
+ /* go back through and remap the expression */
+ for (cur_expr = new_node->expr; cur_expr != NULL;
+ cur_expr = cur_expr->next) {
+ /* expression nodes don't have a bool value of 0 - don't map them */
+ if (cur_expr->expr_type != COND_BOOL)
+ continue;
+ assert(module->map[SYM_BOOLS][cur_expr->bool - 1] != 0);
+ cur_expr->bool =
+ module->map[SYM_BOOLS][cur_expr->bool - 1];
+ }
+ new_node->nbools = cur->nbools;
+ /* FIXME should COND_MAX_BOOLS be used here? */
+ for (i = 0; i < min(cur->nbools, COND_MAX_BOOLS); i++) {
+ uint32_t remapped_id =
+ module->map[SYM_BOOLS][cur->bool_ids[i] - 1];
+ assert(remapped_id != 0);
+ new_node->bool_ids[i] = remapped_id;
+ }
+ new_node->expr_pre_comp = cur->expr_pre_comp;
+
+ if (copy_avrule_list
+ (cur->avtrue_list, &new_node->avtrue_list, module, state)
+ || copy_avrule_list(cur->avfalse_list,
+ &new_node->avfalse_list, module,
+ state)) {
+ goto cleanup;
+ }
+
+ if (*dst == NULL) {
+ *dst = new_node;
+ } else {
+ tail->next = new_node;
+ }
+ tail = new_node;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ cond_node_destroy(new_node);
+ free(new_node);
+ return -1;
+
+}
+
+/*********** functions that copy avrule_decls from module to base ***********/
+
+static int copy_identifiers(link_state_t * state, symtab_t * src_symtab,
+ avrule_decl_t * dest_decl)
+{
+ int i, ret;
+
+ state->dest_decl = dest_decl;
+ for (i = 0; i < SYM_NUM; i++) {
+ if (copy_callback_f[i] != NULL) {
+ ret =
+ hashtab_map(src_symtab[i].table, copy_callback_f[i],
+ state);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+
+ if (hashtab_map(src_symtab[SYM_TYPES].table,
+ type_bounds_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_TYPES].table,
+ alias_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_ROLES].table,
+ role_bounds_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_USERS].table,
+ user_bounds_copy_callback, state))
+ return -1;
+
+ /* then fix bitmaps associated with those newly copied identifiers */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (fix_callback_f[i] != NULL &&
+ hashtab_map(src_symtab[i].table, fix_callback_f[i],
+ state)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int copy_scope_index(scope_index_t * src, scope_index_t * dest,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned int i, j;
+ uint32_t largest_mapped_class_value = 0;
+ ebitmap_node_t *node;
+ /* copy the scoping information for this avrule decl block */
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_t *srcmap = src->scope + i;
+ ebitmap_t *destmap = dest->scope + i;
+ if (copy_callback_f[i] == NULL) {
+ continue;
+ }
+ ebitmap_for_each_bit(srcmap, node, j) {
+ if (ebitmap_node_get_bit(node, j)) {
+ assert(module->map[i][j] != 0);
+ if (ebitmap_set_bit
+ (destmap, module->map[i][j] - 1, 1) != 0) {
+
+ goto cleanup;
+ }
+ if (i == SYM_CLASSES &&
+ largest_mapped_class_value <
+ module->map[SYM_CLASSES][j]) {
+ largest_mapped_class_value =
+ module->map[SYM_CLASSES][j];
+ }
+ }
+ }
+ }
+
+ /* next copy the enabled permissions data */
+ if ((dest->class_perms_map = malloc(largest_mapped_class_value *
+ sizeof(*dest->class_perms_map))) ==
+ NULL) {
+ goto cleanup;
+ }
+ for (i = 0; i < largest_mapped_class_value; i++) {
+ ebitmap_init(dest->class_perms_map + i);
+ }
+ dest->class_perms_len = largest_mapped_class_value;
+ for (i = 0; i < src->class_perms_len; i++) {
+ ebitmap_t *srcmap = src->class_perms_map + i;
+ ebitmap_t *destmap =
+ dest->class_perms_map + module->map[SYM_CLASSES][i] - 1;
+ ebitmap_for_each_bit(srcmap, node, j) {
+ if (ebitmap_node_get_bit(node, j) &&
+ ebitmap_set_bit(destmap, module->perm_map[i][j] - 1,
+ 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int copy_avrule_decl(link_state_t * state, policy_module_t * module,
+ avrule_decl_t * src_decl, avrule_decl_t * dest_decl)
+{
+ int ret;
+
+ /* copy all of the RBAC and TE rules */
+ if (copy_avrule_list
+ (src_decl->avrules, &dest_decl->avrules, module, state) == -1
+ || copy_role_trans_list(src_decl->role_tr_rules,
+ &dest_decl->role_tr_rules, module,
+ state) == -1
+ || copy_role_allow_list(src_decl->role_allow_rules,
+ &dest_decl->role_allow_rules, module,
+ state) == -1
+ || copy_cond_list(src_decl->cond_list, &dest_decl->cond_list,
+ module, state) == -1) {
+ return -1;
+ }
+
+ if (copy_filename_trans_list(src_decl->filename_trans_rules,
+ &dest_decl->filename_trans_rules,
+ module, state))
+ return -1;
+
+ if (copy_range_trans_list(src_decl->range_tr_rules,
+ &dest_decl->range_tr_rules, module, state))
+ return -1;
+
+ /* finally copy any identifiers local to this declaration */
+ ret = copy_identifiers(state, src_decl->symtab, dest_decl);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* then copy required and declared scope indices here */
+ if (copy_scope_index(&src_decl->required, &dest_decl->required,
+ module, state) == -1 ||
+ copy_scope_index(&src_decl->declared, &dest_decl->declared,
+ module, state) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int copy_avrule_block(link_state_t * state, policy_module_t * module,
+ avrule_block_t * block)
+{
+ avrule_block_t *new_block = avrule_block_create();
+ avrule_decl_t *decl, *last_decl = NULL;
+ int ret;
+
+ if (new_block == NULL) {
+ ERR(state->handle, "Out of memory!");
+ ret = -1;
+ goto cleanup;
+ }
+
+ new_block->flags = block->flags;
+
+ for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+ avrule_decl_t *new_decl =
+ avrule_decl_create(state->next_decl_id);
+ if (new_decl == NULL) {
+ ERR(state->handle, "Out of memory!");
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (module->policy->name != NULL) {
+ new_decl->module_name = strdup(module->policy->name);
+ if (new_decl->module_name == NULL) {
+ ERR(state->handle, "Out of memory\n");
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ if (last_decl == NULL) {
+ new_block->branch_list = new_decl;
+ } else {
+ last_decl->next = new_decl;
+ }
+ last_decl = new_decl;
+ state->base->decl_val_to_struct[state->next_decl_id - 1] =
+ new_decl;
+ state->decl_to_mod[state->next_decl_id] = module->policy;
+
+ module->avdecl_map[decl->decl_id] = new_decl->decl_id;
+
+ ret = copy_avrule_decl(state, module, decl, new_decl);
+ if (ret) {
+ goto cleanup;
+ }
+
+ state->next_decl_id++;
+ }
+ state->last_avrule_block->next = new_block;
+ state->last_avrule_block = new_block;
+ return 0;
+
+ cleanup:
+ avrule_block_list_destroy(new_block);
+ return ret;
+}
+
+static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ int ret;
+ char *id = key, *new_id = NULL;
+ scope_datum_t *scope, *base_scope;
+ link_state_t *state = (link_state_t *) data;
+ uint32_t symbol_num = state->symbol_num;
+ uint32_t *avdecl_map = state->cur->avdecl_map;
+
+ scope = (scope_datum_t *) datum;
+
+ /* check if the base already has a scope entry */
+ base_scope = hashtab_search(state->base->scope[symbol_num].table, id);
+ if (base_scope == NULL) {
+ scope_datum_t *new_scope;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_scope =
+ (scope_datum_t *) calloc(1, sizeof(*new_scope))) == NULL) {
+ free(new_id);
+ goto cleanup;
+ }
+ ret = hashtab_insert(state->base->scope[symbol_num].table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_scope);
+ if (ret) {
+ free(new_id);
+ free(new_scope);
+ goto cleanup;
+ }
+ new_scope->scope = SCOPE_REQ; /* this is reset further down */
+ base_scope = new_scope;
+ }
+ if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_DECL) {
+ /* this module declared symbol, so overwrite the old
+ * list with the new decl ids */
+ base_scope->scope = SCOPE_DECL;
+ free(base_scope->decl_ids);
+ base_scope->decl_ids = NULL;
+ base_scope->decl_ids_len = 0;
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ } else if (base_scope->scope == SCOPE_DECL && scope->scope == SCOPE_REQ) {
+ /* this module depended on a symbol that now exists,
+ * so don't do anything */
+ } else if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_REQ) {
+ /* symbol is still required, so add to the list */
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ } else {
+ /* this module declared a symbol, and it was already
+ * declared. only roles and users may be multiply
+ * declared; for all others this is an error. */
+ if (symbol_num != SYM_ROLES && symbol_num != SYM_USERS) {
+ ERR(state->handle,
+ "%s: Duplicate declaration in module: %s %s",
+ state->cur_mod_name,
+ symtab_names[state->symbol_num], id);
+ return -1;
+ }
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ }
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+/* Copy a module over to a base, remapping all values within. After
+ * all identifiers and rules are done, copy the scoping information.
+ * This is when it checks for duplicate declarations. */
+static int copy_module(link_state_t * state, policy_module_t * module)
+{
+ int i, ret;
+ avrule_block_t *cur;
+ state->cur = module;
+ state->cur_mod_name = module->policy->name;
+
+ /* first copy all of the identifiers */
+ ret = copy_identifiers(state, module->policy->symtab, NULL);
+ if (ret) {
+ return ret;
+ }
+
+ /* next copy all of the avrule blocks */
+ for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+ ret = copy_avrule_block(state, module, cur);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ /* then copy the scoping tables */
+ for (i = 0; i < SYM_NUM; i++) {
+ state->symbol_num = i;
+ if (hashtab_map
+ (module->policy->scope[i].table, scope_copy_callback,
+ state)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/***** functions that check requirements and enable blocks in a module ******/
+
+/* borrowed from checkpolicy.c */
+
+struct find_perm_arg {
+ unsigned int valuep;
+ hashtab_key_t key;
+};
+
+static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *varg)
+{
+
+ struct find_perm_arg *arg = varg;
+
+ perm_datum_t *perdatum = (perm_datum_t *) datum;
+ if (arg->valuep == perdatum->s.value) {
+ arg->key = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check if the requirements are met for a single declaration. If all
+ * are met return 1. For the first requirement found to be missing,
+ * if 'missing_sym_num' and 'missing_value' are both not NULL then
+ * write to them the symbol number and value for the missing
+ * declaration. Then return 0 to indicate a missing declaration.
+ * Note that if a declaration had no requirement at all (e.g., an ELSE
+ * block) this returns 1. */
+static int is_decl_requires_met(link_state_t * state,
+ avrule_decl_t * decl,
+ struct missing_requirement *req)
+{
+ /* (This algorithm is very unoptimized. It performs many
+ * redundant checks. A very obvious improvement is to cache
+ * which symbols have been verified, so that they do not need
+ * to be re-checked.) */
+ unsigned int i, j;
+ ebitmap_t *bitmap;
+ char *id, *perm_id;
+ policydb_t *pol = state->base;
+ ebitmap_node_t *node;
+
+ /* check that all symbols have been satisfied */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (i == SYM_CLASSES) {
+ /* classes will be checked during permissions
+ * checking phase below */
+ continue;
+ }
+ bitmap = &decl->required.scope[i];
+ ebitmap_for_each_bit(bitmap, node, j) {
+ if (!ebitmap_node_get_bit(node, j)) {
+ continue;
+ }
+
+ /* check base's scope table */
+ id = pol->sym_val_to_name[i][j];
+ if (!is_id_enabled(id, state->base, i)) {
+ /* this symbol was not found */
+ if (req != NULL) {
+ req->symbol_type = i;
+ req->symbol_value = j + 1;
+ }
+ return 0;
+ }
+ }
+ }
+ /* check that all classes and permissions have been satisfied */
+ for (i = 0; i < decl->required.class_perms_len; i++) {
+
+ bitmap = decl->required.class_perms_map + i;
+ ebitmap_for_each_bit(bitmap, node, j) {
+ struct find_perm_arg fparg;
+ class_datum_t *cladatum;
+ uint32_t perm_value = j + 1;
+ scope_datum_t *scope;
+
+ if (!ebitmap_node_get_bit(node, j)) {
+ continue;
+ }
+ id = pol->p_class_val_to_name[i];
+ cladatum = pol->class_val_to_struct[i];
+
+ scope =
+ hashtab_search(state->base->p_classes_scope.table,
+ id);
+ if (scope == NULL) {
+ ERR(state->handle,
+ "Could not find scope information for class %s",
+ id);
+ return -1;
+ }
+
+ fparg.valuep = perm_value;
+ fparg.key = NULL;
+
+ hashtab_map(cladatum->permissions.table, find_perm,
+ &fparg);
+ if (fparg.key == NULL && cladatum->comdatum != NULL)
+ hashtab_map(cladatum->comdatum->permissions.
+ table, find_perm, &fparg);
+ perm_id = fparg.key;
+
+ assert(perm_id != NULL);
+ if (!is_perm_enabled(id, perm_id, state->base)) {
+ if (req != NULL) {
+ req->symbol_type = SYM_CLASSES;
+ req->symbol_value = i + 1;
+ req->perm_value = perm_value;
+ }
+ return 0;
+ }
+ }
+ }
+
+ /* all requirements have been met */
+ return 1;
+}
+
+static int debug_requirements(link_state_t * state, policydb_t * p)
+{
+ int ret;
+ avrule_block_t *cur;
+ missing_requirement_t req;
+
+ for (cur = p->global; cur != NULL; cur = cur->next) {
+ if (cur->enabled != NULL)
+ continue;
+
+ ret = is_decl_requires_met(state, cur->branch_list, &req);
+ if (ret < 0) {
+ return ret;
+ } else if (ret == 0) {
+ char *mod_name = cur->branch_list->module_name ?
+ cur->branch_list->module_name : "BASE";
+ if (req.symbol_type == SYM_CLASSES) {
+
+ struct find_perm_arg fparg;
+
+ class_datum_t *cladatum;
+ cladatum =
+ p->class_val_to_struct[req.symbol_value -
+ 1];
+
+ fparg.valuep = req.perm_value;
+ fparg.key = NULL;
+ hashtab_map(cladatum->permissions.table,
+ find_perm, &fparg);
+
+ if (cur->flags & AVRULE_OPTIONAL) {
+ ERR(state->handle,
+ "%s[%d]'s optional requirements were not met: class %s, permission %s",
+ mod_name, cur->branch_list->decl_id,
+ p->p_class_val_to_name[req.
+ symbol_value
+ - 1],
+ fparg.key);
+ } else {
+ ERR(state->handle,
+ "%s[%d]'s global requirements were not met: class %s, permission %s",
+ mod_name, cur->branch_list->decl_id,
+ p->p_class_val_to_name[req.
+ symbol_value
+ - 1],
+ fparg.key);
+ }
+ } else {
+ if (cur->flags & AVRULE_OPTIONAL) {
+ ERR(state->handle,
+ "%s[%d]'s optional requirements were not met: %s %s",
+ mod_name, cur->branch_list->decl_id,
+ symtab_names[req.symbol_type],
+ p->sym_val_to_name[req.
+ symbol_type][req.
+ symbol_value
+ -
+ 1]);
+ } else {
+ ERR(state->handle,
+ "%s[%d]'s global requirements were not met: %s %s",
+ mod_name, cur->branch_list->decl_id,
+ symtab_names[req.symbol_type],
+ p->sym_val_to_name[req.
+ symbol_type][req.
+ symbol_value
+ -
+ 1]);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void print_missing_requirements(link_state_t * state,
+ avrule_block_t * cur,
+ missing_requirement_t * req)
+{
+ policydb_t *p = state->base;
+ char *mod_name = cur->branch_list->module_name ?
+ cur->branch_list->module_name : "BASE";
+
+ if (req->symbol_type == SYM_CLASSES) {
+
+ struct find_perm_arg fparg;
+
+ class_datum_t *cladatum;
+ cladatum = p->class_val_to_struct[req->symbol_value - 1];
+
+ fparg.valuep = req->perm_value;
+ fparg.key = NULL;
+ hashtab_map(cladatum->permissions.table, find_perm, &fparg);
+
+ ERR(state->handle,
+ "%s's global requirements were not met: class %s, permission %s",
+ mod_name,
+ p->p_class_val_to_name[req->symbol_value - 1], fparg.key);
+ } else {
+ ERR(state->handle,
+ "%s's global requirements were not met: %s %s",
+ mod_name,
+ symtab_names[req->symbol_type],
+ p->sym_val_to_name[req->symbol_type][req->symbol_value -
+ 1]);
+ }
+}
+
+/* Enable all of the avrule_decl blocks for the policy. This simple
+ * algorithm is the following:
+ *
+ * 1) Enable all of the non-else avrule_decls for all blocks.
+ * 2) Iterate through the non-else decls looking for decls whose requirements
+ * are not met.
+ * 2a) If the decl is non-optional, return immediately with an error.
+ * 2b) If the decl is optional, disable the block and mark changed = 1
+ * 3) If changed == 1 goto 2.
+ * 4) Iterate through all blocks looking for those that have no enabled
+ * decl. If the block has an else decl, enable.
+ *
+ * This will correctly handle all dependencies, including mutual and
+ * cicular. The only downside is that it is slow.
+ */
+static int enable_avrules(link_state_t * state, policydb_t * pol)
+{
+ int changed = 1;
+ avrule_block_t *block;
+ avrule_decl_t *decl;
+ missing_requirement_t req;
+ int ret = 0, rc;
+
+ if (state->verbose) {
+ INFO(state->handle, "Determining which avrules to enable.");
+ }
+
+ /* 1) enable all of the non-else blocks */
+ for (block = pol->global; block != NULL; block = block->next) {
+ block->enabled = block->branch_list;
+ block->enabled->enabled = 1;
+ for (decl = block->branch_list->next; decl != NULL;
+ decl = decl->next)
+ decl->enabled = 0;
+ }
+
+ /* 2) Iterate */
+ while (changed) {
+ changed = 0;
+ for (block = pol->global; block != NULL; block = block->next) {
+ if (block->enabled == NULL) {
+ continue;
+ }
+ decl = block->branch_list;
+ if (state->verbose) {
+ char *mod_name = decl->module_name ?
+ decl->module_name : "BASE";
+ INFO(state->handle, "check module %s decl %d\n",
+ mod_name, decl->decl_id);
+ }
+ rc = is_decl_requires_met(state, decl, &req);
+ if (rc < 0) {
+ ret = SEPOL_ERR;
+ goto out;
+ } else if (rc == 0) {
+ decl->enabled = 0;
+ block->enabled = NULL;
+ changed = 1;
+ if (!(block->flags & AVRULE_OPTIONAL)) {
+ print_missing_requirements(state, block,
+ &req);
+ ret = SEPOL_EREQ;
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* 4) else handling
+ *
+ * Iterate through all of the blocks skipping the first (which is the
+ * global block, is required to be present, and cannot have an else).
+ * If the block is disabled and has an else decl, enable that.
+ *
+ * This code assumes that the second block in the branch list is the else
+ * block. This is currently supported by the compiler.
+ */
+ for (block = pol->global->next; block != NULL; block = block->next) {
+ if (block->enabled == NULL) {
+ if (block->branch_list->next != NULL) {
+ block->enabled = block->branch_list->next;
+ block->branch_list->next->enabled = 1;
+ }
+ }
+ }
+
+ out:
+ if (state->verbose)
+ debug_requirements(state, pol);
+
+ return ret;
+}
+
+/*********** the main linking functions ***********/
+
+/* Given a module's policy, normalize all conditional expressions
+ * within. Return 0 on success, -1 on error. */
+static int cond_normalize(policydb_t * p)
+{
+ avrule_block_t *block;
+ for (block = p->global; block != NULL; block = block->next) {
+ avrule_decl_t *decl;
+ for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+ cond_list_t *cond = decl->cond_list;
+ while (cond) {
+ if (cond_normalize_expr(p, cond) < 0)
+ return -1;
+ cond = cond->next;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Allocate space for the various remapping arrays. */
+static int prepare_module(link_state_t * state, policy_module_t * module)
+{
+ int i;
+ uint32_t items, num_decls = 0;
+ avrule_block_t *cur;
+
+ /* allocate the maps */
+ for (i = 0; i < SYM_NUM; i++) {
+ items = module->policy->symtab[i].nprim;
+ if ((module->map[i] =
+ (uint32_t *) calloc(items,
+ sizeof(*module->map[i]))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+
+ /* allocate the permissions remap here */
+ items = module->policy->p_classes.nprim;
+ if ((module->perm_map_len =
+ calloc(items, sizeof(*module->perm_map_len))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if ((module->perm_map =
+ calloc(items, sizeof(*module->perm_map))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* allocate a map for avrule_decls */
+ for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+ avrule_decl_t *decl;
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (decl->decl_id > num_decls) {
+ num_decls = decl->decl_id;
+ }
+ }
+ }
+ num_decls++;
+ if ((module->avdecl_map = calloc(num_decls, sizeof(uint32_t))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ module->num_decls = num_decls;
+
+ /* normalize conditionals within */
+ if (cond_normalize(module->policy) < 0) {
+ ERR(state->handle,
+ "Error while normalizing conditionals within the module %s.",
+ module->policy->name);
+ return -1;
+ }
+ return 0;
+}
+
+static int prepare_base(link_state_t * state, uint32_t num_mod_decls)
+{
+ avrule_block_t *cur = state->base->global;
+ assert(cur != NULL);
+ state->next_decl_id = 0;
+
+ /* iterate through all of the declarations in the base, to
+ determine what the next decl_id should be */
+ while (cur != NULL) {
+ avrule_decl_t *decl;
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (decl->decl_id > state->next_decl_id) {
+ state->next_decl_id = decl->decl_id;
+ }
+ }
+ state->last_avrule_block = cur;
+ cur = cur->next;
+ }
+ state->last_base_avrule_block = state->last_avrule_block;
+ state->next_decl_id++;
+
+ /* allocate the table mapping from base's decl_id to its
+ * avrule_decls and set the initial mappings */
+ free(state->base->decl_val_to_struct);
+ if ((state->base->decl_val_to_struct =
+ calloc(state->next_decl_id + num_mod_decls,
+ sizeof(*(state->base->decl_val_to_struct)))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ /* This allocates the decl block to module mapping used for error reporting */
+ if ((state->decl_to_mod = calloc(state->next_decl_id + num_mod_decls,
+ sizeof(*(state->decl_to_mod)))) ==
+ NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ cur = state->base->global;
+ while (cur != NULL) {
+ avrule_decl_t *decl = cur->branch_list;
+ while (decl != NULL) {
+ state->base->decl_val_to_struct[decl->decl_id - 1] =
+ decl;
+ state->decl_to_mod[decl->decl_id] = state->base;
+ decl = decl->next;
+ }
+ cur = cur->next;
+ }
+
+ /* normalize conditionals within */
+ if (cond_normalize(state->base) < 0) {
+ ERR(state->handle,
+ "Error while normalizing conditionals within the base module.");
+ return -1;
+ }
+ return 0;
+}
+
+static int expand_role_attributes(hashtab_key_t key, hashtab_datum_t datum,
+ void * data)
+{
+ char *id;
+ role_datum_t *role, *sub_attr;
+ link_state_t *state;
+ unsigned int i;
+ ebitmap_node_t *rnode;
+
+ id = key;
+ role = (role_datum_t *)datum;
+ state = (link_state_t *)data;
+
+ if (strcmp(id, OBJECT_R) == 0){
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ if (state->verbose)
+ INFO(state->handle, "expanding role attribute %s", id);
+
+restart:
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ sub_attr = state->base->role_val_to_struct[i];
+ if (sub_attr->flavor != ROLE_ATTRIB)
+ continue;
+
+ /* remove the sub role attribute from the parent
+ * role attribute's roles ebitmap */
+ if (ebitmap_set_bit(&role->roles, i, 0))
+ return -1;
+
+ /* loop dependency of role attributes */
+ if (sub_attr->s.value == role->s.value)
+ continue;
+
+ /* now go on to expand a sub role attribute
+ * by escalating its roles ebitmap */
+ if (ebitmap_union(&role->roles, &sub_attr->roles)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* sub_attr->roles may contain other role attributes,
+ * re-scan the parent role attribute's roles ebitmap */
+ goto restart;
+ }
+ }
+
+ return 0;
+}
+
+/* For any role attribute in a declaration's local symtab[SYM_ROLES] table,
+ * copy its roles ebitmap into its duplicate's in the base->p_roles.table.
+ */
+static int populate_decl_roleattributes(hashtab_key_t key,
+ hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ role_datum_t *decl_role, *base_role;
+ link_state_t *state = (link_state_t *)data;
+
+ decl_role = (role_datum_t *)datum;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (decl_role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ base_role = (role_datum_t *)hashtab_search(state->base->p_roles.table,
+ id);
+ assert(base_role != NULL && base_role->flavor == ROLE_ATTRIB);
+
+ if (ebitmap_union(&base_role->roles, &decl_role->roles)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int populate_roleattributes(link_state_t *state, policydb_t *pol)
+{
+ avrule_block_t *block;
+ avrule_decl_t *decl;
+
+ if (state->verbose)
+ INFO(state->handle, "Populating role-attribute relationship "
+ "from enabled declarations' local symtab.");
+
+ /* Iterate through all of the blocks skipping the first(which is the
+ * global block, is required to be present and can't have an else).
+ * If the block is disabled or not having an enabled decl, skip it.
+ */
+ for (block = pol->global->next; block != NULL; block = block->next)
+ {
+ decl = block->enabled;
+ if (decl == NULL || decl->enabled == 0)
+ continue;
+
+ if (hashtab_map(decl->symtab[SYM_ROLES].table,
+ populate_decl_roleattributes, state))
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Link a set of modules into a base module. This process is somewhat
+ * similar to an actual compiler: it requires a set of order dependent
+ * steps. The base and every module must have been indexed prior to
+ * calling this function.
+ */
+int link_modules(sepol_handle_t * handle,
+ policydb_t * b, policydb_t ** mods, int len, int verbose)
+{
+ int i, ret, retval = -1;
+ policy_module_t **modules = NULL;
+ link_state_t state;
+ uint32_t num_mod_decls = 0;
+
+ memset(&state, 0, sizeof(state));
+ state.base = b;
+ state.verbose = verbose;
+ state.handle = handle;
+
+ if (b->policy_type != POLICY_BASE) {
+ ERR(state.handle, "Target of link was not a base policy.");
+ return -1;
+ }
+
+ /* first allocate some space to hold the maps from module
+ * symbol's value to the destination symbol value; then do
+ * other preparation work */
+ if ((modules =
+ (policy_module_t **) calloc(len, sizeof(*modules))) == NULL) {
+ ERR(state.handle, "Out of memory!");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ if (mods[i]->policy_type != POLICY_MOD) {
+ ERR(state.handle,
+ "Tried to link in a policy that was not a module.");
+ goto cleanup;
+ }
+
+ if (mods[i]->mls != b->mls) {
+ if (b->mls)
+ ERR(state.handle,
+ "Tried to link in a non-MLS module with an MLS base.");
+ else
+ ERR(state.handle,
+ "Tried to link in an MLS module with a non-MLS base.");
+ goto cleanup;
+ }
+
+ if ((modules[i] =
+ (policy_module_t *) calloc(1,
+ sizeof(policy_module_t))) ==
+ NULL) {
+ ERR(state.handle, "Out of memory!");
+ goto cleanup;
+ }
+ modules[i]->policy = mods[i];
+ if (prepare_module(&state, modules[i]) == -1) {
+ goto cleanup;
+ }
+ num_mod_decls += modules[i]->num_decls;
+ }
+ if (prepare_base(&state, num_mod_decls) == -1) {
+ goto cleanup;
+ }
+
+ /* copy all types, declared and required */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ state.cur_mod_name = modules[i]->policy->name;
+ ret =
+ hashtab_map(modules[i]->policy->p_types.table,
+ type_copy_callback, &state);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ /* then copy everything else, including aliases, and fixup attributes */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ state.cur_mod_name = modules[i]->policy->name;
+ ret =
+ copy_identifiers(&state, modules[i]->policy->symtab, NULL);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ if (policydb_index_others(state.handle, state.base, 0)) {
+ ERR(state.handle, "Error while indexing others");
+ goto cleanup;
+ }
+
+ /* copy and remap the module's data over to base */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ ret = copy_module(&state, modules[i]);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ /* re-index base, for symbols were added to symbol tables */
+ if (policydb_index_classes(state.base)) {
+ ERR(state.handle, "Error while indexing classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(state.handle, state.base, 0)) {
+ ERR(state.handle, "Error while indexing others");
+ goto cleanup;
+ }
+
+ if (enable_avrules(&state, state.base)) {
+ retval = SEPOL_EREQ;
+ goto cleanup;
+ }
+
+ /* Now that all role attribute's roles ebitmap have been settled,
+ * escalate sub role attribute's roles ebitmap into that of parent.
+ *
+ * First, since some role-attribute relationships could be recorded
+ * in some decl's local symtab(see get_local_role()), we need to
+ * populate them up to the base.p_roles table. */
+ if (populate_roleattributes(&state, state.base)) {
+ retval = SEPOL_EREQ;
+ goto cleanup;
+ }
+
+ /* Now do the escalation. */
+ if (hashtab_map(state.base->p_roles.table, expand_role_attributes,
+ &state))
+ goto cleanup;
+
+ retval = 0;
+ cleanup:
+ for (i = 0; modules != NULL && i < len; i++) {
+ policy_module_destroy(modules[i]);
+ }
+ free(modules);
+ free(state.decl_to_mod);
+ return retval;
+}
diff --git a/src/mls.c b/src/mls.c
new file mode 100644
index 0000000..1e84bb7
--- /dev/null
+++ b/src/mls.c
@@ -0,0 +1,798 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the multi-level security (MLS) policy.
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/context.h>
+
+#include <stdlib.h>
+
+#include "handle.h"
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+int mls_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * mls, char **str)
+{
+
+ char *ptr = NULL, *ptr2 = NULL;
+
+ /* Temporary buffer - length + NULL terminator */
+ int len = mls_compute_context_len(policydb, mls) + 1;
+
+ ptr = (char *)malloc(len);
+ if (ptr == NULL)
+ goto omem;
+
+ /* Final string w/ ':' cut off */
+ ptr2 = (char *)malloc(len - 1);
+ if (ptr2 == NULL)
+ goto omem;
+
+ mls_sid_to_context(policydb, mls, &ptr);
+ ptr -= len - 1;
+ strcpy(ptr2, ptr + 1);
+
+ free(ptr);
+ *str = ptr2;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not convert mls context to string");
+
+ free(ptr);
+ free(ptr2);
+ return STATUS_ERR;
+
+}
+
+int mls_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const char *str, context_struct_t * mls)
+{
+
+ char *tmp = strdup(str);
+ char *tmp_cp = tmp;
+ if (!tmp)
+ goto omem;
+
+ if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
+ ERR(handle, "invalid MLS context %s", str);
+ free(tmp);
+ goto err;
+ }
+
+ free(tmp);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not construct mls context structure");
+ return STATUS_ERR;
+}
+
+/*
+ * Return the length in bytes for the MLS fields of the
+ * security context string representation of `context'.
+ */
+int mls_compute_context_len(const policydb_t * policydb,
+ const context_struct_t * context)
+{
+
+ unsigned int i, l, len, range;
+ ebitmap_node_t *cnode;
+
+ if (!policydb->mls)
+ return 0;
+
+ len = 1; /* for the beginning ":" */
+ for (l = 0; l < 2; l++) {
+ range = 0;
+ len +=
+ strlen(policydb->
+ p_sens_val_to_name[context->range.level[l].sens -
+ 1]);
+
+ ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (range) {
+ range++;
+ continue;
+ }
+
+ len +=
+ strlen(policydb->p_cat_val_to_name[i]) + 1;
+ range++;
+ } else {
+ if (range > 1)
+ len +=
+ strlen(policydb->
+ p_cat_val_to_name[i - 1]) +
+ 1;
+ range = 0;
+ }
+ }
+ /* Handle case where last category is the end of range */
+ if (range > 1)
+ len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
+
+ if (l == 0) {
+ if (mls_level_eq(&context->range.level[0],
+ &context->range.level[1]))
+ break;
+ else
+ len++;
+ }
+ }
+
+ return len;
+}
+
+/*
+ * Write the security context string representation of
+ * the MLS fields of `context' into the string `*scontext'.
+ * Update `*scontext' to point to the end of the MLS fields.
+ */
+void mls_sid_to_context(const policydb_t * policydb,
+ const context_struct_t * context, char **scontext)
+{
+
+ char *scontextp;
+ unsigned int i, l, range, wrote_sep;
+ ebitmap_node_t *cnode;
+
+ if (!policydb->mls)
+ return;
+
+ scontextp = *scontext;
+
+ *scontextp = ':';
+ scontextp++;
+
+ for (l = 0; l < 2; l++) {
+ range = 0;
+ wrote_sep = 0;
+ strcpy(scontextp,
+ policydb->p_sens_val_to_name[context->range.level[l].
+ sens - 1]);
+ scontextp +=
+ strlen(policydb->
+ p_sens_val_to_name[context->range.level[l].sens -
+ 1]);
+ /* categories */
+ ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (range) {
+ range++;
+ continue;
+ }
+
+ if (!wrote_sep) {
+ *scontextp++ = ':';
+ wrote_sep = 1;
+ } else
+ *scontextp++ = ',';
+ strcpy(scontextp,
+ policydb->p_cat_val_to_name[i]);
+ scontextp +=
+ strlen(policydb->p_cat_val_to_name[i]);
+ range++;
+ } else {
+ if (range > 1) {
+ if (range > 2)
+ *scontextp++ = '.';
+ else
+ *scontextp++ = ',';
+
+ strcpy(scontextp,
+ policydb->p_cat_val_to_name[i -
+ 1]);
+ scontextp +=
+ strlen(policydb->
+ p_cat_val_to_name[i - 1]);
+ }
+ range = 0;
+ }
+ }
+ /* Handle case where last category is the end of range */
+ if (range > 1) {
+ if (range > 2)
+ *scontextp++ = '.';
+ else
+ *scontextp++ = ',';
+
+ strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
+ scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
+ }
+
+ if (l == 0) {
+ if (mls_level_eq(&context->range.level[0],
+ &context->range.level[1]))
+ break;
+ else {
+ *scontextp = '-';
+ scontextp++;
+ }
+ }
+ }
+
+ *scontext = scontextp;
+ return;
+}
+
+/*
+ * Return 1 if the MLS fields in the security context
+ * structure `c' are valid. Return 0 otherwise.
+ */
+int mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+ level_datum_t *levdatum;
+ user_datum_t *usrdatum;
+ unsigned int i, l;
+ ebitmap_node_t *cnode;
+
+ if (!p->mls)
+ return 1;
+
+ /*
+ * MLS range validity checks: high must dominate low, low level must
+ * be valid (category set <-> sensitivity check), and high level must
+ * be valid (category set <-> sensitivity check)
+ */
+ if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
+ /* High does not dominate low. */
+ return 0;
+
+ for (l = 0; l < 2; l++) {
+ if (!c->range.level[l].sens
+ || c->range.level[l].sens > p->p_levels.nprim)
+ return 0;
+ levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+ p->
+ p_sens_val_to_name
+ [c->range.level[l].
+ sens - 1]);
+ if (!levdatum)
+ return 0;
+
+ ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
+ }
+ }
+ }
+
+ if (c->role == OBJECT_R_VAL)
+ return 1;
+
+ /*
+ * User must be authorized for the MLS range.
+ */
+ if (!c->user || c->user > p->p_users.nprim)
+ return 0;
+ usrdatum = p->user_val_to_struct[c->user - 1];
+ if (!mls_range_contains(usrdatum->exp_range, c->range))
+ return 0; /* user may not be associated with range */
+
+ return 1;
+}
+
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'. Update `*scontext' to
+ * point to the end of the string representation of
+ * the MLS fields.
+ *
+ * This function modifies the string in place, inserting
+ * NULL characters to terminate the MLS fields.
+ */
+int mls_context_to_sid(const policydb_t * policydb,
+ char oldc, char **scontext, context_struct_t * context)
+{
+
+ char delim;
+ char *scontextp, *p, *rngptr;
+ level_datum_t *levdatum;
+ cat_datum_t *catdatum, *rngdatum;
+ unsigned int l;
+
+ if (!policydb->mls)
+ return 0;
+
+ /* No MLS component to the security context */
+ if (!oldc)
+ goto err;
+
+ /* Extract low sensitivity. */
+ scontextp = p = *scontext;
+ while (*p && *p != ':' && *p != '-')
+ p++;
+
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+
+ for (l = 0; l < 2; l++) {
+ levdatum =
+ (level_datum_t *) hashtab_search(policydb->p_levels.table,
+ (hashtab_key_t) scontextp);
+
+ if (!levdatum)
+ goto err;
+
+ context->range.level[l].sens = levdatum->level->sens;
+
+ if (delim == ':') {
+ /* Extract category set. */
+ while (1) {
+ scontextp = p;
+ while (*p && *p != ',' && *p != '-')
+ p++;
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+
+ /* Separate into range if exists */
+ if ((rngptr = strchr(scontextp, '.')) != NULL) {
+ /* Remove '.' */
+ *rngptr++ = 0;
+ }
+
+ catdatum =
+ (cat_datum_t *) hashtab_search(policydb->
+ p_cats.table,
+ (hashtab_key_t)
+ scontextp);
+ if (!catdatum)
+ goto err;
+
+ if (ebitmap_set_bit
+ (&context->range.level[l].cat,
+ catdatum->s.value - 1, 1))
+ goto err;
+
+ /* If range, set all categories in range */
+ if (rngptr) {
+ unsigned int i;
+
+ rngdatum = (cat_datum_t *)
+ hashtab_search(policydb->p_cats.
+ table,
+ (hashtab_key_t)
+ rngptr);
+ if (!rngdatum)
+ goto err;
+
+ if (catdatum->s.value >=
+ rngdatum->s.value)
+ goto err;
+
+ for (i = catdatum->s.value;
+ i < rngdatum->s.value; i++) {
+ if (ebitmap_set_bit
+ (&context->range.level[l].
+ cat, i, 1))
+ goto err;
+ }
+ }
+
+ if (delim != ',')
+ break;
+ }
+ }
+ if (delim == '-') {
+ /* Extract high sensitivity. */
+ scontextp = p;
+ while (*p && *p != ':')
+ p++;
+
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+ } else
+ break;
+ }
+
+ /* High level is missing, copy low level */
+ if (l == 0) {
+ if (mls_level_cpy(&context->range.level[1],
+ &context->range.level[0]) < 0)
+ goto err;
+ }
+ *scontext = ++p;
+
+ return STATUS_SUCCESS;
+
+ err:
+ return STATUS_ERR;
+}
+
+/*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(context_struct_t * dst,
+ context_struct_t * src)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range from the source context */
+ for (l = 0; l < 2; l++) {
+ dst->range.level[l].sens = src->range.level[l].sens;
+ rc = ebitmap_cpy(&dst->range.level[l].cat,
+ &src->range.level[l].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(context_struct_t * dst,
+ context_struct_t * src)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range from the source context */
+ for (l = 0; l < 2; l++) {
+ dst->range.level[l].sens = src->range.level[0].sens;
+ rc = ebitmap_cpy(&dst->range.level[l].cat,
+ &src->range.level[0].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(context_struct_t * context, mls_range_t * range)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range into the context */
+ for (l = 0; l < 2; l++) {
+ context->range.level[l].sens = range->level[l].sens;
+ rc = ebitmap_cpy(&context->range.level[l].cat,
+ &range->level[l].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+ context_struct_t * usercon, int mls)
+{
+ if (mls) {
+ mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
+ mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
+ mls_level_t *user_low = &(user->exp_range.level[0]);
+ mls_level_t *user_clr = &(user->exp_range.level[1]);
+ mls_level_t *user_def = &(user->exp_dfltlevel);
+ mls_level_t *usercon_sen = &(usercon->range.level[0]);
+ mls_level_t *usercon_clr = &(usercon->range.level[1]);
+
+ /* Honor the user's default level if we can */
+ if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+ *usercon_sen = *user_def;
+ } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+ *usercon_sen = *fromcon_sen;
+ } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+ *usercon_sen = *user_low;
+ } else
+ return -EINVAL;
+
+ /* Lower the clearance of available contexts
+ if the clearance of "fromcon" is lower than
+ that of the user's default clearance (but
+ only if the "fromcon" clearance dominates
+ the user's computed sensitivity level) */
+ if (mls_level_dom(user_clr, fromcon_clr)) {
+ *usercon_clr = *fromcon_clr;
+ } else if (mls_level_dom(fromcon_clr, user_clr)) {
+ *usercon_clr = *user_clr;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert the MLS fields in the security context
+ * structure `c' from the values specified in the
+ * policy `oldp' to the values specified in the policy `newp'.
+ */
+int mls_convert_context(policydb_t * oldp,
+ policydb_t * newp, context_struct_t * c)
+{
+ level_datum_t *levdatum;
+ cat_datum_t *catdatum;
+ ebitmap_t bitmap;
+ unsigned int l, i;
+ ebitmap_node_t *cnode;
+
+ if (!oldp->mls)
+ return 0;
+
+ for (l = 0; l < 2; l++) {
+ levdatum =
+ (level_datum_t *) hashtab_search(newp->p_levels.table,
+ oldp->
+ p_sens_val_to_name[c->
+ range.
+ level
+ [l].
+ sens -
+ 1]);
+
+ if (!levdatum)
+ return -EINVAL;
+ c->range.level[l].sens = levdatum->level->sens;
+
+ ebitmap_init(&bitmap);
+ ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ int rc;
+
+ catdatum =
+ (cat_datum_t *) hashtab_search(newp->p_cats.
+ table,
+ oldp->
+ p_cat_val_to_name
+ [i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap,
+ catdatum->s.value - 1, 1);
+ if (rc)
+ return rc;
+ }
+ }
+ ebitmap_destroy(&c->range.level[l].cat);
+ c->range.level[l].cat = bitmap;
+ }
+
+ return 0;
+}
+
+int mls_compute_sid(policydb_t * policydb,
+ context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ uint32_t specified, context_struct_t * newcontext)
+{
+ range_trans_t *rtr;
+ if (!policydb->mls)
+ return 0;
+
+ switch (specified) {
+ case AVTAB_TRANSITION:
+ /* Look for a range transition rule. */
+ for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
+ if (rtr->source_type == scontext->type &&
+ rtr->target_type == tcontext->type &&
+ rtr->target_class == tclass) {
+ /* Set the range from the rule */
+ return mls_range_set(newcontext,
+ &rtr->target_range);
+ }
+ }
+ /* Fallthrough */
+ case AVTAB_CHANGE:
+ if (tclass == SECCLASS_PROCESS)
+ /* Use the process MLS attributes. */
+ return mls_copy_context(newcontext, scontext);
+ else
+ /* Use the process effective MLS attributes. */
+ return mls_scopy_context(newcontext, scontext);
+ case AVTAB_MEMBER:
+ /* Only polyinstantiate the MLS attributes if
+ the type is being polyinstantiated */
+ if (newcontext->type != tcontext->type) {
+ /* Use the process effective MLS attributes. */
+ return mls_scopy_context(newcontext, scontext);
+ } else {
+ /* Use the related object MLS attributes. */
+ return mls_copy_context(newcontext, tcontext);
+ }
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+int sepol_mls_contains(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const char *mls1, const char *mls2, int *response)
+{
+
+ context_struct_t *ctx1 = NULL, *ctx2 = NULL;
+ ctx1 = malloc(sizeof(context_struct_t));
+ ctx2 = malloc(sizeof(context_struct_t));
+ if (ctx1 == NULL || ctx2 == NULL)
+ goto omem;
+ context_init(ctx1);
+ context_init(ctx2);
+
+ if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
+ goto err;
+
+ if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
+ goto err;
+
+ *response = mls_range_contains(ctx1->range, ctx2->range);
+ context_destroy(ctx1);
+ context_destroy(ctx2);
+ free(ctx1);
+ free(ctx2);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not check if mls context %s contains %s",
+ mls1, mls2);
+ context_destroy(ctx1);
+ context_destroy(ctx2);
+ free(ctx1);
+ free(ctx2);
+ return STATUS_ERR;
+}
+
+int sepol_mls_check(sepol_handle_t * handle,
+ sepol_policydb_t * policydb, const char *mls)
+{
+
+ int ret;
+ context_struct_t *con = malloc(sizeof(context_struct_t));
+ if (!con) {
+ ERR(handle, "out of memory, could not check if "
+ "mls context %s is valid", mls);
+ return STATUS_ERR;
+ }
+ context_init(con);
+
+ ret = mls_from_string(handle, &policydb->p, mls, con);
+ context_destroy(con);
+ free(con);
+ return ret;
+}
+
+void mls_semantic_cat_init(mls_semantic_cat_t * c)
+{
+ memset(c, 0, sizeof(mls_semantic_cat_t));
+}
+
+void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
+{
+ /* it's currently a simple struct - really nothing to destroy */
+ return;
+}
+
+void mls_semantic_level_init(mls_semantic_level_t * l)
+{
+ memset(l, 0, sizeof(mls_semantic_level_t));
+}
+
+void mls_semantic_level_destroy(mls_semantic_level_t * l)
+{
+ mls_semantic_cat_t *cur, *next;
+
+ if (l == NULL)
+ return;
+
+ next = l->cat;
+ while (next) {
+ cur = next;
+ next = cur->next;
+ mls_semantic_cat_destroy(cur);
+ free(cur);
+ }
+}
+
+int mls_semantic_level_cpy(mls_semantic_level_t * dst,
+ mls_semantic_level_t * src)
+{
+ mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL;
+
+ mls_semantic_level_init(dst);
+ dst->sens = src->sens;
+ cat = src->cat;
+ while (cat) {
+ newcat =
+ (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!newcat)
+ goto err;
+
+ mls_semantic_cat_init(newcat);
+ if (lnewcat)
+ lnewcat->next = newcat;
+ else
+ dst->cat = newcat;
+
+ newcat->low = cat->low;
+ newcat->high = cat->high;
+
+ lnewcat = newcat;
+ cat = cat->next;
+ }
+ return 0;
+
+ err:
+ mls_semantic_level_destroy(dst);
+ return -1;
+}
+
+void mls_semantic_range_init(mls_semantic_range_t * r)
+{
+ mls_semantic_level_init(&r->level[0]);
+ mls_semantic_level_init(&r->level[1]);
+}
+
+void mls_semantic_range_destroy(mls_semantic_range_t * r)
+{
+ mls_semantic_level_destroy(&r->level[0]);
+ mls_semantic_level_destroy(&r->level[1]);
+}
+
+int mls_semantic_range_cpy(mls_semantic_range_t * dst,
+ mls_semantic_range_t * src)
+{
+ if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
+ return -1;
+
+ if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
+ mls_semantic_level_destroy(&dst->level[0]);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/mls.h b/src/mls.h
new file mode 100644
index 0000000..98da3d3
--- /dev/null
+++ b/src/mls.h
@@ -0,0 +1,67 @@
+/* Author: Stephen Smalley, <sds@epoch.ncsc.mil>
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_MLS_INTERNAL_H_
+#define _SEPOL_MLS_INTERNAL_H_
+
+#include "policydb_internal.h"
+#include <sepol/policydb/context.h>
+#include "handle.h"
+
+extern int mls_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const char *str, context_struct_t * mls);
+
+extern int mls_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * mls, char **str);
+
+/* Deprecated */
+extern int mls_compute_context_len(const policydb_t * policydb,
+ const context_struct_t * context);
+
+/* Deprecated */
+extern void mls_sid_to_context(const policydb_t * policydb,
+ const context_struct_t * context,
+ char **scontext);
+
+/* Deprecated */
+extern int mls_context_to_sid(const policydb_t * policydb,
+ char oldc,
+ char **scontext, context_struct_t * context);
+
+extern int mls_context_isvalid(const policydb_t * p,
+ const context_struct_t * c);
+
+extern int mls_convert_context(policydb_t * oldp,
+ policydb_t * newp, context_struct_t * context);
+
+extern int mls_compute_sid(policydb_t * policydb,
+ context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ uint32_t specified, context_struct_t * newcontext);
+
+extern int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+ context_struct_t * usercon, int mls);
+
+#endif
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 0000000..b5b807e
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,985 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policydb_internal.h"
+#include "module_internal.h"
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/module.h>
+#include "debug.h"
+#include "private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
+#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
+#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
+#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
+
+static int policy_file_seek(struct policy_file *fp, size_t offset)
+{
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ if (offset > LONG_MAX) {
+ errno = EFAULT;
+ return -1;
+ }
+ return fseek(fp->fp, (long)offset, SEEK_SET);
+ case PF_USE_MEMORY:
+ if (offset > fp->size) {
+ errno = EFAULT;
+ return -1;
+ }
+ fp->data -= fp->size - fp->len;
+ fp->data += offset;
+ fp->len = fp->size - offset;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static size_t policy_file_length(struct policy_file *fp)
+{
+ long prev_offset, end_offset;
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ prev_offset = ftell(fp->fp);
+ fseek(fp->fp, 0L, SEEK_END);
+ end_offset = ftell(fp->fp);
+ fseek(fp->fp, prev_offset, SEEK_SET);
+ return end_offset;
+ case PF_USE_MEMORY:
+ return fp->size;
+ default:
+ return 0;
+ }
+}
+
+static int module_package_init(sepol_module_package_t * p)
+{
+ memset(p, 0, sizeof(sepol_module_package_t));
+ if (sepol_policydb_create(&p->policy))
+ return -1;
+
+ p->version = 1;
+ return 0;
+}
+
+static int set_char(char **field, char *data, size_t len)
+{
+ if (*field) {
+ free(*field);
+ *field = NULL;
+ }
+ if (len) {
+ *field = malloc(len);
+ if (!*field)
+ return -1;
+ memcpy(*field, data, len);
+ }
+ return 0;
+}
+
+int sepol_module_package_create(sepol_module_package_t ** p)
+{
+ *p = calloc(1, sizeof(sepol_module_package_t));
+ if (!(*p))
+ return -1;
+ return module_package_init(*p);
+}
+
+hidden_def(sepol_module_package_create)
+
+/* Deallocates all memory associated with a module package, including
+ * the pointer itself. Does nothing if p is NULL.
+ */
+void sepol_module_package_free(sepol_module_package_t * p)
+{
+ if (p == NULL)
+ return;
+
+ sepol_policydb_free(p->policy);
+ free(p->file_contexts);
+ free(p->seusers);
+ free(p->user_extra);
+ free(p->netfilter_contexts);
+ free(p);
+}
+
+hidden_def(sepol_module_package_free)
+
+char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
+{
+ return p->file_contexts;
+}
+
+size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
+{
+ return p->file_contexts_len;
+}
+
+char *sepol_module_package_get_seusers(sepol_module_package_t * p)
+{
+ return p->seusers;
+}
+
+size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
+{
+ return p->seusers_len;
+}
+
+char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
+{
+ return p->user_extra;
+}
+
+size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
+{
+ return p->user_extra_len;
+}
+
+char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
+{
+ return p->netfilter_contexts;
+}
+
+size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
+ p)
+{
+ return p->netfilter_contexts_len;
+}
+
+int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->file_contexts, data, len))
+ return -1;
+
+ p->file_contexts_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_seusers(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->seusers, data, len))
+ return -1;
+
+ p->seusers_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->user_extra, data, len))
+ return -1;
+
+ p->user_extra_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->netfilter_contexts, data, len))
+ return -1;
+
+ p->netfilter_contexts_len = len;
+ return 0;
+}
+
+sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
+{
+ return p->policy;
+}
+
+/* Append each of the file contexts from each module to the base
+ * policy's file context. 'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_fc_len' is the length of base's file context; it
+ * too is a reference variable. Return 0 on success, -1 if out of
+ * memory. */
+static int link_file_contexts(sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules)
+{
+ size_t fc_len;
+ int i;
+ char *s;
+
+ fc_len = base->file_contexts_len;
+ for (i = 0; i < num_modules; i++) {
+ fc_len += modules[i]->file_contexts_len;
+ }
+
+ if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
+ return -1;
+ }
+ base->file_contexts = s;
+ for (i = 0; i < num_modules; i++) {
+ memcpy(base->file_contexts + base->file_contexts_len,
+ modules[i]->file_contexts,
+ modules[i]->file_contexts_len);
+ base->file_contexts_len += modules[i]->file_contexts_len;
+ }
+ return 0;
+}
+
+/* Append each of the netfilter contexts from each module to the base
+ * policy's netfilter context. 'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_nc_len' is the length of base's netfilter contexts; it
+ * too is a reference variable. Return 0 on success, -1 if out of
+ * memory. */
+static int link_netfilter_contexts(sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules)
+{
+ size_t base_nc_len;
+ int i;
+ char *base_context;
+
+ base_nc_len = base->netfilter_contexts_len;
+ for (i = 0; i < num_modules; i++) {
+ base_nc_len += modules[i]->netfilter_contexts_len;
+ }
+
+ if ((base_context =
+ (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
+ return -1;
+ }
+ base->netfilter_contexts = base_context;
+ for (i = 0; i < num_modules; i++) {
+ memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
+ modules[i]->netfilter_contexts,
+ modules[i]->netfilter_contexts_len);
+ base->netfilter_contexts_len +=
+ modules[i]->netfilter_contexts_len;
+ }
+ return 0;
+}
+
+/* Links the module packages into the base. Returns 0 on success, -1
+ * if a requirement was not met, or -2 for all other errors. */
+int sepol_link_packages(sepol_handle_t * handle,
+ sepol_module_package_t * base,
+ sepol_module_package_t ** modules, int num_modules,
+ int verbose)
+{
+ policydb_t **mod_pols = NULL;
+ int i, retval;
+
+ if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+ for (i = 0; i < num_modules; i++) {
+ mod_pols[i] = &modules[i]->policy->p;
+ }
+
+ retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
+ verbose);
+ free(mod_pols);
+ if (retval == -3) {
+ return -1;
+ } else if (retval < 0) {
+ return -2;
+ }
+
+ if (link_file_contexts(base, modules, num_modules) == -1) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+
+ if (link_netfilter_contexts(base, modules, num_modules) == -1) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+
+ return 0;
+}
+
+/* buf must be large enough - no checks are performed */
+#define _read_helper_bufsize BUFSIZ
+static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
+{
+ uint32_t offset, nel, read_len;
+ int rc;
+
+ offset = 0;
+ nel = bytes;
+
+ while (nel) {
+ if (nel < _read_helper_bufsize)
+ read_len = nel;
+ else
+ read_len = _read_helper_bufsize;
+ rc = next_entry(&buf[offset], file, read_len);
+ if (rc < 0)
+ return -1;
+ offset += read_len;
+ nel -= read_len;
+ }
+ return 0;
+}
+
+#define MAXSECTIONS 100
+
+/* Get the section offsets from a package file, offsets will be malloc'd to
+ * the appropriate size and the caller must free() them */
+static int module_package_read_offsets(sepol_module_package_t * mod,
+ struct policy_file *file,
+ size_t ** offsets, uint32_t * sections)
+{
+ uint32_t *buf = NULL, nsec;
+ unsigned i;
+ size_t *off = NULL;
+ int rc;
+
+ buf = malloc(sizeof(uint32_t)*3);
+ if (!buf) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+
+ rc = next_entry(buf, file, sizeof(uint32_t) * 3);
+ if (rc < 0) {
+ ERR(file->handle, "module package header truncated");
+ goto err;
+ }
+ if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
+ ERR(file->handle,
+ "wrong magic number for module package: expected %#08x, got %#08x",
+ SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
+ goto err;
+ }
+
+ mod->version = le32_to_cpu(buf[1]);
+ nsec = *sections = le32_to_cpu(buf[2]);
+
+ if (nsec > MAXSECTIONS) {
+ ERR(file->handle, "too many sections (%u) in module package",
+ nsec);
+ goto err;
+ }
+
+ off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
+ if (!off) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+
+ free(buf);
+ buf = malloc(sizeof(uint32_t) * nsec);
+ if (!buf) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+ rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
+ if (rc < 0) {
+ ERR(file->handle, "module package offset array truncated");
+ goto err;
+ }
+
+ for (i = 0; i < nsec; i++) {
+ off[i] = le32_to_cpu(buf[i]);
+ if (i && off[i] < off[i - 1]) {
+ ERR(file->handle, "offsets are not increasing (at %u, "
+ "offset %zu -> %zu", i, off[i - 1],
+ off[i]);
+ goto err;
+ }
+ }
+
+ off[nsec] = policy_file_length(file);
+ if (nsec && off[nsec] < off[nsec-1]) {
+ ERR(file->handle, "offset greater than file size (at %u, "
+ "offset %zu -> %zu", nsec, off[nsec - 1],
+ off[nsec]);
+ goto err;
+ }
+ *offsets = off;
+ free(buf);
+ return 0;
+
+err:
+ free(buf);
+ free(off);
+ return -1;
+}
+
+/* Flags for which sections have been seen during parsing of module package. */
+#define SEEN_MOD 1
+#define SEEN_FC 2
+#define SEEN_SEUSER 4
+#define SEEN_USER_EXTRA 8
+#define SEEN_NETFILTER 16
+
+int sepol_module_package_read(sepol_module_package_t * mod,
+ struct sepol_policy_file *spf, int verbose)
+{
+ struct policy_file *file = &spf->pf;
+ uint32_t buf[1], nsec;
+ size_t *offsets, len;
+ int rc;
+ unsigned i, seen = 0;
+
+ if (module_package_read_offsets(mod, file, &offsets, &nsec))
+ return -1;
+
+ /* we know the section offsets, seek to them and read in the data */
+
+ for (i = 0; i < nsec; i++) {
+
+ if (policy_file_seek(file, offsets[i])) {
+ ERR(file->handle, "error seeking to offset %zu for "
+ "module package section %u", offsets[i], i);
+ goto cleanup;
+ }
+
+ len = offsets[i + 1] - offsets[i];
+
+ if (len < sizeof(uint32_t)) {
+ ERR(file->handle, "module package section %u "
+ "has too small length %zu", i, len);
+ goto cleanup;
+ }
+
+ /* read the magic number, so that we know which function to call */
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "module package section %u truncated, lacks magic number",
+ i);
+ goto cleanup;
+ }
+
+ switch (le32_to_cpu(buf[0])) {
+ case SEPOL_PACKAGE_SECTION_FC:
+ if (seen & SEEN_FC) {
+ ERR(file->handle,
+ "found multiple file contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->file_contexts_len = len - sizeof(uint32_t);
+ mod->file_contexts =
+ (char *)malloc(mod->file_contexts_len);
+ if (!mod->file_contexts) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->file_contexts, file,
+ mod->file_contexts_len)) {
+ ERR(file->handle,
+ "invalid file contexts section at section %u",
+ i);
+ free(mod->file_contexts);
+ mod->file_contexts = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_FC;
+ break;
+ case SEPOL_PACKAGE_SECTION_SEUSER:
+ if (seen & SEEN_SEUSER) {
+ ERR(file->handle,
+ "found multiple seuser sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->seusers_len = len - sizeof(uint32_t);
+ mod->seusers = (char *)malloc(mod->seusers_len);
+ if (!mod->seusers) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper(mod->seusers, file, mod->seusers_len)) {
+ ERR(file->handle,
+ "invalid seuser section at section %u", i);
+ free(mod->seusers);
+ mod->seusers = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_SEUSER;
+ break;
+ case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+ if (seen & SEEN_USER_EXTRA) {
+ ERR(file->handle,
+ "found multiple user_extra sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->user_extra_len = len - sizeof(uint32_t);
+ mod->user_extra = (char *)malloc(mod->user_extra_len);
+ if (!mod->user_extra) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->user_extra, file, mod->user_extra_len)) {
+ ERR(file->handle,
+ "invalid user_extra section at section %u",
+ i);
+ free(mod->user_extra);
+ mod->user_extra = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_USER_EXTRA;
+ break;
+ case SEPOL_PACKAGE_SECTION_NETFILTER:
+ if (seen & SEEN_NETFILTER) {
+ ERR(file->handle,
+ "found multiple netfilter contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->netfilter_contexts_len = len - sizeof(uint32_t);
+ mod->netfilter_contexts =
+ (char *)malloc(mod->netfilter_contexts_len);
+ if (!mod->netfilter_contexts) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->netfilter_contexts, file,
+ mod->netfilter_contexts_len)) {
+ ERR(file->handle,
+ "invalid netfilter contexts section at section %u",
+ i);
+ free(mod->netfilter_contexts);
+ mod->netfilter_contexts = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_NETFILTER;
+ break;
+ case POLICYDB_MOD_MAGIC:
+ if (seen & SEEN_MOD) {
+ ERR(file->handle,
+ "found multiple module sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ /* seek back to where the magic number was */
+ if (policy_file_seek(file, offsets[i]))
+ goto cleanup;
+
+ rc = policydb_read(&mod->policy->p, file, verbose);
+ if (rc < 0) {
+ ERR(file->handle,
+ "invalid module in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_MOD;
+ break;
+ default:
+ /* unknown section, ignore */
+ ERR(file->handle,
+ "unknown magic number at section %u, offset: %zx, number: %ux ",
+ i, offsets[i], le32_to_cpu(buf[0]));
+ break;
+ }
+ }
+
+ if ((seen & SEEN_MOD) == 0) {
+ ERR(file->handle, "missing module in module package");
+ goto cleanup;
+ }
+
+ free(offsets);
+ return 0;
+
+ cleanup:
+ free(offsets);
+ return -1;
+}
+
+int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
+ char **name, char **version)
+{
+ struct policy_file *file = &spf->pf;
+ sepol_module_package_t *mod = NULL;
+ uint32_t buf[5], len, nsec;
+ size_t *offsets = NULL;
+ unsigned i, seen = 0;
+ char *id;
+ int rc;
+
+ if (sepol_module_package_create(&mod))
+ return -1;
+
+ if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < nsec; i++) {
+
+ if (policy_file_seek(file, offsets[i])) {
+ ERR(file->handle, "error seeking to offset "
+ "%zu for module package section %u", offsets[i], i);
+ goto cleanup;
+ }
+
+ len = offsets[i + 1] - offsets[i];
+
+ if (len < sizeof(uint32_t)) {
+ ERR(file->handle,
+ "module package section %u has too small length %u",
+ i, len);
+ goto cleanup;
+ }
+
+ /* read the magic number, so that we know which function to call */
+ rc = next_entry(buf, file, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(file->handle,
+ "module package section %u truncated, lacks magic number",
+ i);
+ goto cleanup;
+ }
+
+ switch (le32_to_cpu(buf[0])) {
+ case SEPOL_PACKAGE_SECTION_FC:
+ /* skip file contexts */
+ if (seen & SEEN_FC) {
+ ERR(file->handle,
+ "found multiple file contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_FC;
+ break;
+ case SEPOL_PACKAGE_SECTION_SEUSER:
+ /* skip seuser */
+ if (seen & SEEN_SEUSER) {
+ ERR(file->handle,
+ "found seuser sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_SEUSER;
+ break;
+ case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+ /* skip user_extra */
+ if (seen & SEEN_USER_EXTRA) {
+ ERR(file->handle,
+ "found user_extra sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_USER_EXTRA;
+ break;
+ case SEPOL_PACKAGE_SECTION_NETFILTER:
+ /* skip netfilter contexts */
+ if (seen & SEEN_NETFILTER) {
+ ERR(file->handle,
+ "found multiple netfilter contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_NETFILTER;
+ break;
+ case POLICYDB_MOD_MAGIC:
+ if (seen & SEEN_MOD) {
+ ERR(file->handle,
+ "found multiple module sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[1]);
+ if (len != strlen(POLICYDB_MOD_STRING)) {
+ ERR(file->handle,
+ "module string length is wrong (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ /* skip id */
+ id = malloc(len + 1);
+ if (!id) {
+ ERR(file->handle,
+ "out of memory (at section %u)",
+ i);
+ goto cleanup;
+ }
+ rc = next_entry(id, file, len);
+ free(id);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module string (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ rc = next_entry(buf, file, sizeof(uint32_t) * 5);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module header (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ *type = le32_to_cpu(buf[0]);
+ /* if base - we're done */
+ if (*type == POLICY_BASE) {
+ *name = NULL;
+ *version = NULL;
+ seen |= SEEN_MOD;
+ break;
+ } else if (*type != POLICY_MOD) {
+ ERR(file->handle,
+ "module has invalid type %d (at section %u)",
+ *type, i);
+ goto cleanup;
+ }
+
+ /* read the name and version */
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module name len (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[0]);
+ *name = malloc(len + 1);
+ if (!*name) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ rc = next_entry(*name, file, len);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module name string (at section %u)",
+ i);
+ goto cleanup;
+ }
+ (*name)[len] = '\0';
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module version len (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[0]);
+ *version = malloc(len + 1);
+ if (!*version) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ rc = next_entry(*version, file, len);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module version string (at section %u)",
+ i);
+ goto cleanup;
+ }
+ (*version)[len] = '\0';
+ seen |= SEEN_MOD;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ if ((seen & SEEN_MOD) == 0) {
+ ERR(file->handle, "missing module in module package");
+ goto cleanup;
+ }
+
+ sepol_module_package_free(mod);
+ free(offsets);
+ return 0;
+
+ cleanup:
+ sepol_module_package_free(mod);
+ free(offsets);
+ return -1;
+}
+
+static int write_helper(char *data, size_t len, struct policy_file *file)
+{
+ int idx = 0;
+ size_t len2;
+
+ while (len) {
+ if (len > BUFSIZ)
+ len2 = BUFSIZ;
+ else
+ len2 = len;
+
+ if (put_entry(&data[idx], 1, len2, file) != len2) {
+ return -1;
+ }
+ len -= len2;
+ idx += len2;
+ }
+ return 0;
+}
+
+int sepol_module_package_write(sepol_module_package_t * p,
+ struct sepol_policy_file *spf)
+{
+ struct policy_file *file = &spf->pf;
+ policy_file_t polfile;
+ uint32_t buf[5], offsets[5], len, nsec = 0;
+ int i;
+
+ if (p->policy) {
+ /* compute policy length */
+ policy_file_init(&polfile);
+ polfile.type = PF_LEN;
+ polfile.handle = file->handle;
+ if (policydb_write(&p->policy->p, &polfile))
+ return -1;
+ len = polfile.len;
+ if (!polfile.len)
+ return -1;
+ nsec++;
+
+ } else {
+ /* We don't support writing a package without a module at this point */
+ return -1;
+ }
+
+ /* seusers and user_extra only supported in base at the moment */
+ if ((p->seusers || p->user_extra)
+ && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
+ ERR(file->handle,
+ "seuser and user_extra sections only supported in base");
+ return -1;
+ }
+
+ if (p->file_contexts)
+ nsec++;
+
+ if (p->seusers)
+ nsec++;
+
+ if (p->user_extra)
+ nsec++;
+
+ if (p->netfilter_contexts)
+ nsec++;
+
+ buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
+ buf[1] = cpu_to_le32(p->version);
+ buf[2] = cpu_to_le32(nsec);
+ if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
+ return -1;
+
+ /* calculate offsets */
+ offsets[0] = (nsec + 3) * sizeof(uint32_t);
+ buf[0] = cpu_to_le32(offsets[0]);
+
+ i = 1;
+ if (p->file_contexts) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ /* add a uint32_t to compensate for the magic number */
+ len = p->file_contexts_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->seusers) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->seusers_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->user_extra) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->user_extra_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->netfilter_contexts) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->netfilter_contexts_len + sizeof(uint32_t);
+ i++;
+ }
+ if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
+ return -1;
+
+ /* write sections */
+
+ if (policydb_write(&p->policy->p, file))
+ return -1;
+
+ if (p->file_contexts) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->file_contexts, p->file_contexts_len, file))
+ return -1;
+ }
+ if (p->seusers) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->seusers, p->seusers_len, file))
+ return -1;
+
+ }
+ if (p->user_extra) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->user_extra, p->user_extra_len, file))
+ return -1;
+ }
+ if (p->netfilter_contexts) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper
+ (p->netfilter_contexts, p->netfilter_contexts_len, file))
+ return -1;
+ }
+ return 0;
+}
+
+int sepol_link_modules(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t ** modules, size_t len, int verbose)
+{
+ return link_modules(handle, &base->p, (policydb_t **) modules, len,
+ verbose);
+}
+
+int sepol_expand_module(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t * out, int verbose, int check)
+{
+ return expand_module(handle, &base->p, &out->p, verbose, check);
+}
diff --git a/src/module_internal.h b/src/module_internal.h
new file mode 100644
index 0000000..cdd5ec6
--- /dev/null
+++ b/src/module_internal.h
@@ -0,0 +1,5 @@
+#include <sepol/module.h>
+#include "dso.h"
+
+hidden_proto(sepol_module_package_create)
+ hidden_proto(sepol_module_package_free)
diff --git a/src/node_internal.h b/src/node_internal.h
new file mode 100644
index 0000000..802cda9
--- /dev/null
+++ b/src/node_internal.h
@@ -0,0 +1,26 @@
+#ifndef _SEPOL_NODE_INTERNAL_H_
+#define _SEPOL_NODE_INTERNAL_H_
+
+#include <sepol/node_record.h>
+#include <sepol/nodes.h>
+#include "dso.h"
+
+hidden_proto(sepol_node_create)
+ hidden_proto(sepol_node_key_free)
+ hidden_proto(sepol_node_free)
+ hidden_proto(sepol_node_get_con)
+ hidden_proto(sepol_node_get_addr)
+ hidden_proto(sepol_node_get_addr_bytes)
+ hidden_proto(sepol_node_get_mask)
+ hidden_proto(sepol_node_get_mask_bytes)
+ hidden_proto(sepol_node_get_proto)
+ hidden_proto(sepol_node_get_proto_str)
+ hidden_proto(sepol_node_key_create)
+ hidden_proto(sepol_node_key_unpack)
+ hidden_proto(sepol_node_set_con)
+ hidden_proto(sepol_node_set_addr)
+ hidden_proto(sepol_node_set_addr_bytes)
+ hidden_proto(sepol_node_set_mask)
+ hidden_proto(sepol_node_set_mask_bytes)
+ hidden_proto(sepol_node_set_proto)
+#endif
diff --git a/src/node_record.c b/src/node_record.c
new file mode 100644
index 0000000..b1bd370
--- /dev/null
+++ b/src/node_record.c
@@ -0,0 +1,668 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "node_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_node {
+
+ /* Network address and mask */
+ char *addr;
+ size_t addr_sz;
+
+ char *mask;
+ size_t mask_sz;
+
+ /* Protocol */
+ int proto;
+
+ /* Context */
+ sepol_context_t *con;
+};
+
+struct sepol_node_key {
+
+ /* Network address and mask */
+ char *addr;
+ size_t addr_sz;
+
+ char *mask;
+ size_t mask_sz;
+
+ /* Protocol */
+ int proto;
+};
+
+/* Converts a string represtation (addr_str)
+ * to a numeric representation (addr_bytes) */
+
+static int node_parse_addr(sepol_handle_t * handle,
+ const char *addr_str, int proto, char *addr_bytes)
+{
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ struct in_addr in_addr;
+
+ if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) {
+ ERR(handle, "could not parse IPv4 address "
+ "%s: %s", addr_str, strerror(errno));
+ return STATUS_ERR;
+ }
+
+ memcpy(addr_bytes, &in_addr.s_addr, 4);
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ struct in6_addr in_addr;
+
+ if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) {
+ ERR(handle, "could not parse IPv6 address "
+ "%s: %s", addr_str, strerror(errno));
+ return STATUS_ERR;
+ }
+
+ memcpy(addr_bytes, in_addr.s6_addr32, 16);
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u, could not "
+ "parse address", proto);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large buffer (addr, addr_sz)
+ * according the the protocol */
+
+static int node_alloc_addr(sepol_handle_t * handle,
+ int proto, char **addr, size_t * addr_sz)
+{
+
+ char *tmp_addr = NULL;
+ size_t tmp_addr_sz;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ tmp_addr_sz = 4;
+ tmp_addr = malloc(4);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ tmp_addr_sz = 16;
+ tmp_addr = malloc(16);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *addr = tmp_addr;
+ *addr_sz = tmp_addr_sz;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not allocate address of protocol %s",
+ sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Converts a numeric representation (addr_bytes)
+ * to a string representation (addr_str), according to
+ * the protocol */
+
+static int node_expand_addr(sepol_handle_t * handle,
+ char *addr_bytes, int proto, char *addr_str)
+{
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ struct in_addr addr;
+ memset(&addr, 0, sizeof(struct in_addr));
+ memcpy(&addr.s_addr, addr_bytes, 4);
+
+ if (inet_ntop(AF_INET, &addr, addr_str,
+ INET_ADDRSTRLEN) == NULL) {
+
+ ERR(handle,
+ "could not expand IPv4 address to string: %s",
+ strerror(errno));
+ return STATUS_ERR;
+ }
+ break;
+ }
+
+ case SEPOL_PROTO_IP6:
+ {
+ struct in6_addr addr;
+ memset(&addr, 0, sizeof(struct in6_addr));
+ memcpy(&addr.s6_addr32[0], addr_bytes, 16);
+
+ if (inet_ntop(AF_INET6, &addr, addr_str,
+ INET6_ADDRSTRLEN) == NULL) {
+
+ ERR(handle,
+ "could not expand IPv6 address to string: %s",
+ strerror(errno));
+ return STATUS_ERR;
+ }
+ break;
+ }
+
+ default:
+ ERR(handle, "unsupported protocol %u, could not"
+ " expand address to string", proto);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large address string (addr)
+ * according to the protocol */
+
+static int node_alloc_addr_string(sepol_handle_t * handle,
+ int proto, char **addr)
+{
+
+ char *tmp_addr = NULL;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ tmp_addr = malloc(INET_ADDRSTRLEN);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ tmp_addr = malloc(INET6_ADDRSTRLEN);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *addr = tmp_addr;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not allocate string buffer for "
+ "address of protocol %s", sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Key */
+int sepol_node_key_create(sepol_handle_t * handle,
+ const char *addr,
+ const char *mask,
+ int proto, sepol_node_key_t ** key_ptr)
+{
+
+ sepol_node_key_t *tmp_key =
+ (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+ if (!tmp_key)
+ goto omem;
+
+ if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) <
+ 0)
+ goto err;
+ if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0)
+ goto err;
+
+ if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) <
+ 0)
+ goto err;
+ if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0)
+ goto err;
+
+ tmp_key->proto = proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ sepol_node_key_free(tmp_key);
+ ERR(handle, "could not create node key for (%s, %s, %s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_key_create)
+
+void sepol_node_key_unpack(const sepol_node_key_t * key,
+ const char **addr, const char **mask, int *proto)
+{
+
+ *addr = key->addr;
+ *mask = key->mask;
+ *proto = key->proto;
+}
+
+hidden_def(sepol_node_key_unpack)
+
+int sepol_node_key_extract(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_key_t ** key_ptr)
+{
+
+ sepol_node_key_t *tmp_key =
+ (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+ if (!tmp_key)
+ goto omem;
+
+ tmp_key->addr = malloc(node->addr_sz);
+ tmp_key->mask = malloc(node->mask_sz);
+
+ if (!tmp_key->addr || !tmp_key->mask)
+ goto omem;
+
+ memcpy(tmp_key->addr, node->addr, node->addr_sz);
+ memcpy(tmp_key->mask, node->mask, node->mask_sz);
+ tmp_key->addr_sz = node->addr_sz;
+ tmp_key->mask_sz = node->mask_sz;
+ tmp_key->proto = node->proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+
+ omem:
+ sepol_node_key_free(tmp_key);
+ ERR(handle, "out of memory, could not extract node key");
+ return STATUS_ERR;
+}
+
+void sepol_node_key_free(sepol_node_key_t * key)
+{
+
+ if (!key)
+ return;
+
+ free(key->addr);
+ free(key->mask);
+ free(key);
+}
+
+hidden_def(sepol_node_key_free)
+
+int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key)
+{
+
+ int rc1, rc2;
+
+ if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz))
+ return -1;
+
+ else if ((node->addr_sz > key->addr_sz) ||
+ (node->mask_sz > key->mask_sz))
+ return 1;
+
+ rc1 = memcmp(node->addr, key->addr, node->addr_sz);
+ rc2 = memcmp(node->mask, key->mask, node->mask_sz);
+
+ return (rc2 != 0) ? rc2 : rc1;
+}
+
+int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2)
+{
+
+ int rc1, rc2;
+
+ if ((node->addr_sz < node2->addr_sz) ||
+ (node->mask_sz < node2->mask_sz))
+ return -1;
+
+ else if ((node->addr_sz > node2->addr_sz) ||
+ (node->mask_sz > node2->mask_sz))
+ return 1;
+
+ rc1 = memcmp(node->addr, node2->addr, node->addr_sz);
+ rc2 = memcmp(node->mask, node2->mask, node->mask_sz);
+
+ return (rc2 != 0) ? rc2 : rc1;
+}
+
+/* Addr */
+int sepol_node_get_addr(sepol_handle_t * handle,
+ const sepol_node_t * node, char **addr)
+{
+
+ char *tmp_addr = NULL;
+
+ if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0)
+ goto err;
+
+ if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0)
+ goto err;
+
+ *addr = tmp_addr;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not get node address");
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_addr)
+
+int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **buffer, size_t * bsize)
+{
+
+ char *tmp_buf = malloc(node->addr_sz);
+ if (!tmp_buf) {
+ ERR(handle, "out of memory, could not get address bytes");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_buf, node->addr, node->addr_sz);
+ *buffer = tmp_buf;
+ *bsize = node->addr_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_addr_bytes)
+
+int sepol_node_set_addr(sepol_handle_t * handle,
+ sepol_node_t * node, int proto, const char *addr)
+{
+
+ char *tmp_addr = NULL;
+ size_t tmp_addr_sz;
+
+ if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0)
+ goto err;
+
+ if (node_parse_addr(handle, addr, proto, tmp_addr) < 0)
+ goto err;
+
+ free(node->addr);
+ node->addr = tmp_addr;
+ node->addr_sz = tmp_addr_sz;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not set node address to %s", addr);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_addr)
+
+int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *addr, size_t addr_sz)
+{
+
+ char *tmp_addr = malloc(addr_sz);
+ if (!tmp_addr) {
+ ERR(handle, "out of memory, could not " "set node address");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_addr, addr, addr_sz);
+ free(node->addr);
+ node->addr = tmp_addr;
+ node->addr_sz = addr_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_addr_bytes)
+
+/* Mask */
+int sepol_node_get_mask(sepol_handle_t * handle,
+ const sepol_node_t * node, char **mask)
+{
+
+ char *tmp_mask = NULL;
+
+ if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0)
+ goto err;
+
+ if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0)
+ goto err;
+
+ *mask = tmp_mask;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_mask);
+ ERR(handle, "could not get node netmask");
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_mask)
+
+int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **buffer, size_t * bsize)
+{
+
+ char *tmp_buf = malloc(node->mask_sz);
+ if (!tmp_buf) {
+ ERR(handle, "out of memory, could not get netmask bytes");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_buf, node->mask, node->mask_sz);
+ *buffer = tmp_buf;
+ *bsize = node->mask_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_mask_bytes)
+
+int sepol_node_set_mask(sepol_handle_t * handle,
+ sepol_node_t * node, int proto, const char *mask)
+{
+
+ char *tmp_mask = NULL;
+ size_t tmp_mask_sz;
+
+ if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0)
+ goto err;
+
+ if (node_parse_addr(handle, mask, proto, tmp_mask) < 0)
+ goto err;
+
+ free(node->mask);
+ node->mask = tmp_mask;
+ node->mask_sz = tmp_mask_sz;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_mask);
+ ERR(handle, "could not set node netmask to %s", mask);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_mask)
+
+int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *mask, size_t mask_sz)
+{
+
+ char *tmp_mask = malloc(mask_sz);
+ if (!tmp_mask) {
+ ERR(handle, "out of memory, could not " "set node netmask");
+ return STATUS_ERR;
+ }
+ memcpy(tmp_mask, mask, mask_sz);
+ free(node->mask);
+ node->mask = tmp_mask;
+ node->mask_sz = mask_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_mask_bytes)
+
+/* Protocol */
+int sepol_node_get_proto(const sepol_node_t * node)
+{
+
+ return node->proto;
+}
+
+hidden_def(sepol_node_get_proto)
+
+void sepol_node_set_proto(sepol_node_t * node, int proto)
+{
+
+ node->proto = proto;
+}
+
+hidden_def(sepol_node_set_proto)
+
+const char *sepol_node_get_proto_str(int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_IP4:
+ return "ipv4";
+ case SEPOL_PROTO_IP6:
+ return "ipv6";
+ default:
+ return "???";
+ }
+}
+
+hidden_def(sepol_node_get_proto_str)
+
+/* Create */
+int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node)
+{
+
+ sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t));
+
+ if (!tmp_node) {
+ ERR(handle, "out of memory, could not create " "node record");
+ return STATUS_ERR;
+ }
+
+ tmp_node->addr = NULL;
+ tmp_node->addr_sz = 0;
+ tmp_node->mask = NULL;
+ tmp_node->mask_sz = 0;
+ tmp_node->proto = SEPOL_PROTO_IP4;
+ tmp_node->con = NULL;
+ *node = tmp_node;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_create)
+
+/* Deep copy clone */
+int sepol_node_clone(sepol_handle_t * handle,
+ const sepol_node_t * node, sepol_node_t ** node_ptr)
+{
+
+ sepol_node_t *new_node = NULL;
+ if (sepol_node_create(handle, &new_node) < 0)
+ goto err;
+
+ /* Copy address, mask, protocol */
+ new_node->addr = malloc(node->addr_sz);
+ new_node->mask = malloc(node->mask_sz);
+ if (!new_node->addr || !new_node->mask)
+ goto omem;
+
+ memcpy(new_node->addr, node->addr, node->addr_sz);
+ memcpy(new_node->mask, node->mask, node->mask_sz);
+ new_node->addr_sz = node->addr_sz;
+ new_node->mask_sz = node->mask_sz;
+ new_node->proto = node->proto;
+
+ /* Copy context */
+ if (node->con &&
+ (sepol_context_clone(handle, node->con, &new_node->con) < 0))
+ goto err;
+
+ *node_ptr = new_node;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not clone node record");
+ sepol_node_free(new_node);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_node_free(sepol_node_t * node)
+{
+
+ if (!node)
+ return;
+
+ sepol_context_free(node->con);
+ free(node->addr);
+ free(node->mask);
+ free(node);
+}
+
+hidden_def(sepol_node_free)
+
+/* Context */
+sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
+{
+
+ return node->con;
+}
+
+hidden_def(sepol_node_get_con)
+
+int sepol_node_set_con(sepol_handle_t * handle,
+ sepol_node_t * node, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set node context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(node->con);
+ node->con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_con)
diff --git a/src/nodes.c b/src/nodes.c
new file mode 100644
index 0000000..ebf5f1d
--- /dev/null
+++ b/src/nodes.c
@@ -0,0 +1,400 @@
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "node_internal.h"
+
+/* Create a low level node structure from
+ * a high level representation */
+static int node_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** node, const sepol_node_t * data)
+{
+
+ ocontext_t *tmp_node = NULL;
+ context_struct_t *tmp_con = NULL;
+ char *addr_buf = NULL, *mask_buf = NULL;
+
+ tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_node)
+ goto omem;
+
+ size_t addr_bsize, mask_bsize;
+
+ /* Address and netmask */
+ if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
+ goto err;
+ if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
+ goto err;
+
+ int proto = sepol_node_get_proto(data);
+
+ switch (proto) {
+ case SEPOL_PROTO_IP4:
+ memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
+ memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
+ break;
+ case SEPOL_PROTO_IP6:
+ memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
+ memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
+ break;
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+ free(addr_buf);
+ free(mask_buf);
+ addr_buf = NULL;
+ mask_buf = NULL;
+
+ /* Context */
+ if (context_from_record(handle, policydb, &tmp_con,
+ sepol_node_get_con(data)) < 0)
+ goto err;
+ context_cpy(&tmp_node->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *node = tmp_node;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_node != NULL) {
+ context_destroy(&tmp_node->context[0]);
+ free(tmp_node);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ free(addr_buf);
+ free(mask_buf);
+ ERR(handle, "could not create node structure");
+ return STATUS_ERR;
+}
+
+static int node_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * node, int proto, sepol_node_t ** record)
+{
+
+ context_struct_t *con = &node->context[0];
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_node_t *tmp_record = NULL;
+
+ if (sepol_node_create(handle, &tmp_record) < 0)
+ goto err;
+
+ sepol_node_set_proto(tmp_record, proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ if (sepol_node_set_addr_bytes(handle, tmp_record,
+ (const char *)&node->u.node.addr,
+ 4) < 0)
+ goto err;
+
+ if (sepol_node_set_mask_bytes(handle, tmp_record,
+ (const char *)&node->u.node.mask,
+ 4) < 0)
+ goto err;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ if (sepol_node_set_addr_bytes(handle, tmp_record,
+ (const char *)&node->u.node6.addr,
+ 16) < 0)
+ goto err;
+
+ if (sepol_node_set_mask_bytes(handle, tmp_record,
+ (const char *)&node->u.node6.mask,
+ 16) < 0)
+ goto err;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+ goto err;
+
+ if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
+ goto err;
+
+ sepol_context_free(tmp_con);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert node to record");
+ sepol_context_free(tmp_con);
+ sepol_node_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+/* Check if a node exists */
+int sepol_node_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_node_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int proto;
+ const char *addr, *mask;
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = &c->u.node.addr;
+ unsigned int *mask2 = &c->u.node.mask;
+
+ if (!memcmp(addr, addr2, 4) &&
+ !memcmp(mask, mask2, 4)) {
+
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = c->u.node6.addr;
+ unsigned int *mask2 = c->u.node6.mask;
+
+ if (!memcmp(addr, addr2, 16) &&
+ !memcmp(mask, mask2, 16)) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *response = 0;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not check if node %s/%s (%s) exists",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Query a node */
+int sepol_node_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_node_key_t * key, sepol_node_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int proto;
+ const char *addr, *mask;
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = &c->u.node.addr;
+ unsigned int *mask2 = &c->u.node.mask;
+
+ if (!memcmp(addr, addr2, 4) &&
+ !memcmp(mask, mask2, 4)) {
+
+ if (node_to_record(handle, policydb,
+ c, SEPOL_PROTO_IP4,
+ response) < 0)
+ goto err;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = c->u.node6.addr;
+ unsigned int *mask2 = c->u.node6.mask;
+
+ if (!memcmp(addr, addr2, 16) &&
+ !memcmp(mask, mask2, 16)) {
+
+ if (node_to_record(handle, policydb,
+ c, SEPOL_PROTO_IP6,
+ response) < 0)
+ goto err;
+ }
+ }
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query node %s/%s (%s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+
+}
+
+/* Load a node into policy */
+int sepol_node_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_node_key_t * key, const sepol_node_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *node = NULL;
+
+ int proto;
+ const char *addr, *mask;
+
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ if (node_from_record(handle, policydb, &node, data) < 0)
+ goto err;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ /* Attach to context list */
+ node->next = policydb->ocontexts[OCON_NODE];
+ policydb->ocontexts[OCON_NODE] = node;
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ /* Attach to context list */
+ node->next = policydb->ocontexts[OCON_NODE6];
+ policydb->ocontexts[OCON_NODE6] = node;
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not load node %s/%s (%s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ if (node != NULL) {
+ context_destroy(&node->context[0]);
+ free(node);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_node_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_node_t * node,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_node_t *node = NULL;
+ int status;
+
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
+ < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(node, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_node_free(node);
+ node = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
+ < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(node, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_node_free(node);
+ node = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over nodes");
+ sepol_node_free(node);
+ return STATUS_ERR;
+}
diff --git a/src/polcaps.c b/src/polcaps.c
new file mode 100644
index 0000000..71970b1
--- /dev/null
+++ b/src/polcaps.c
@@ -0,0 +1,33 @@
+/*
+ * Policy capability support functions
+ */
+
+#include <string.h>
+#include <sepol/policydb/polcaps.h>
+
+static const char *polcap_names[] = {
+ "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */
+ "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */
+ NULL
+};
+
+int sepol_polcap_getnum(const char *name)
+{
+ int capnum;
+
+ for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) {
+ if (polcap_names[capnum] == NULL)
+ continue;
+ if (strcasecmp(polcap_names[capnum], name) == 0)
+ return capnum;
+ }
+ return -1;
+}
+
+const char *sepol_polcap_getname(int capnum)
+{
+ if (capnum > POLICYDB_CAPABILITY_MAX)
+ return NULL;
+
+ return polcap_names[capnum];
+}
diff --git a/src/policydb.c b/src/policydb.c
new file mode 100644
index 0000000..53d0fda
--- /dev/null
+++ b/src/policydb.c
@@ -0,0 +1,3843 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the policy database.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/flask.h>
+
+#include "private.h"
+#include "debug.h"
+#include "mls.h"
+
+#define POLICYDB_TARGET_SZ ARRAY_SIZE(policydb_target_strings)
+char *policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING };
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_XEN_PCIDEVICE + 1,
+ .target_platform = SEPOL_TARGET_XEN,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM - 3,
+ .ocon_num = OCON_FSUSE + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOOL,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_FSUSE + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_IPV6,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_NLCLASS,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_AVTAB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_RANGETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_MLS_USERS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_MLS_USERS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+};
+
+#if 0
+static char *symtab_name[SYM_NUM] = {
+ "common prefixes",
+ "classes",
+ "roles",
+ "types",
+ "users",
+ "bools" mls_symtab_names cond_symtab_names
+};
+#endif
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+ 2,
+ 32,
+ 16,
+ 512,
+ 128,
+ 16,
+ 16,
+ 16,
+};
+
+struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+ unsigned int type,
+ unsigned int target_platform)
+{
+ unsigned int i;
+ struct policydb_compat_info *info = NULL;
+
+ for (i = 0; i < sizeof(policydb_compat) / sizeof(*info); i++) {
+ if (policydb_compat[i].version == version &&
+ policydb_compat[i].type == type &&
+ policydb_compat[i].target_platform == target_platform) {
+ info = &policydb_compat[i];
+ break;
+ }
+ }
+ return info;
+}
+
+void type_set_init(type_set_t * x)
+{
+ memset(x, 0, sizeof(type_set_t));
+ ebitmap_init(&x->types);
+ ebitmap_init(&x->negset);
+}
+
+void type_set_destroy(type_set_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->types);
+ ebitmap_destroy(&x->negset);
+ }
+}
+
+void role_set_init(role_set_t * x)
+{
+ memset(x, 0, sizeof(role_set_t));
+ ebitmap_init(&x->roles);
+}
+
+void role_set_destroy(role_set_t * x)
+{
+ ebitmap_destroy(&x->roles);
+}
+
+void role_datum_init(role_datum_t * x)
+{
+ memset(x, 0, sizeof(role_datum_t));
+ ebitmap_init(&x->dominates);
+ type_set_init(&x->types);
+ ebitmap_init(&x->cache);
+ ebitmap_init(&x->roles);
+}
+
+void role_datum_destroy(role_datum_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->dominates);
+ type_set_destroy(&x->types);
+ ebitmap_destroy(&x->cache);
+ ebitmap_destroy(&x->roles);
+ }
+}
+
+void type_datum_init(type_datum_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ ebitmap_init(&x->types);
+}
+
+void type_datum_destroy(type_datum_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->types);
+ }
+}
+
+void user_datum_init(user_datum_t * x)
+{
+ memset(x, 0, sizeof(user_datum_t));
+ role_set_init(&x->roles);
+ mls_semantic_range_init(&x->range);
+ mls_semantic_level_init(&x->dfltlevel);
+ ebitmap_init(&x->cache);
+ mls_range_init(&x->exp_range);
+ mls_level_init(&x->exp_dfltlevel);
+}
+
+void user_datum_destroy(user_datum_t * x)
+{
+ if (x != NULL) {
+ role_set_destroy(&x->roles);
+ mls_semantic_range_destroy(&x->range);
+ mls_semantic_level_destroy(&x->dfltlevel);
+ ebitmap_destroy(&x->cache);
+ mls_range_destroy(&x->exp_range);
+ mls_level_destroy(&x->exp_dfltlevel);
+ }
+}
+
+void level_datum_init(level_datum_t * x)
+{
+ memset(x, 0, sizeof(level_datum_t));
+}
+
+void level_datum_destroy(level_datum_t * x __attribute__ ((unused)))
+{
+ /* the mls_level_t referenced by the level_datum is managed
+ * separately for now, so there is nothing to destroy */
+ return;
+}
+
+void cat_datum_init(cat_datum_t * x)
+{
+ memset(x, 0, sizeof(cat_datum_t));
+}
+
+void cat_datum_destroy(cat_datum_t * x __attribute__ ((unused)))
+{
+ /* it's currently a simple struct - really nothing to destroy */
+ return;
+}
+
+void class_perm_node_init(class_perm_node_t * x)
+{
+ memset(x, 0, sizeof(class_perm_node_t));
+}
+
+void avrule_init(avrule_t * x)
+{
+ memset(x, 0, sizeof(avrule_t));
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+}
+
+void avrule_destroy(avrule_t * x)
+{
+ class_perm_node_t *cur, *next;
+
+ if (x == NULL) {
+ return;
+ }
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+
+ next = x->perms;
+ while (next) {
+ cur = next;
+ next = cur->next;
+ free(cur);
+ }
+}
+
+void role_trans_rule_init(role_trans_rule_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ role_set_init(&x->roles);
+ type_set_init(&x->types);
+ ebitmap_init(&x->classes);
+}
+
+void role_trans_rule_destroy(role_trans_rule_t * x)
+{
+ if (x != NULL) {
+ role_set_destroy(&x->roles);
+ type_set_destroy(&x->types);
+ ebitmap_destroy(&x->classes);
+ }
+}
+
+void role_trans_rule_list_destroy(role_trans_rule_t * x)
+{
+ while (x != NULL) {
+ role_trans_rule_t *next = x->next;
+ role_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void filename_trans_rule_init(filename_trans_rule_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+}
+
+static void filename_trans_rule_destroy(filename_trans_rule_t * x)
+{
+ if (!x)
+ return;
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+ free(x->name);
+}
+
+void filename_trans_rule_list_destroy(filename_trans_rule_t * x)
+{
+ filename_trans_rule_t *next;
+ while (x) {
+ next = x->next;
+ filename_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void role_allow_rule_init(role_allow_rule_t * x)
+{
+ memset(x, 0, sizeof(role_allow_rule_t));
+ role_set_init(&x->roles);
+ role_set_init(&x->new_roles);
+}
+
+void role_allow_rule_destroy(role_allow_rule_t * x)
+{
+ role_set_destroy(&x->roles);
+ role_set_destroy(&x->new_roles);
+}
+
+void role_allow_rule_list_destroy(role_allow_rule_t * x)
+{
+ while (x != NULL) {
+ role_allow_rule_t *next = x->next;
+ role_allow_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void range_trans_rule_init(range_trans_rule_t * x)
+{
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+ ebitmap_init(&x->tclasses);
+ mls_semantic_range_init(&x->trange);
+ x->next = NULL;
+}
+
+void range_trans_rule_destroy(range_trans_rule_t * x)
+{
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+ ebitmap_destroy(&x->tclasses);
+ mls_semantic_range_destroy(&x->trange);
+}
+
+void range_trans_rule_list_destroy(range_trans_rule_t * x)
+{
+ while (x != NULL) {
+ range_trans_rule_t *next = x->next;
+ range_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void avrule_list_destroy(avrule_t * x)
+{
+ avrule_t *next, *cur;
+
+ if (!x)
+ return;
+
+ next = x;
+ while (next) {
+ cur = next;
+ next = next->next;
+ avrule_destroy(cur);
+ free(cur);
+ }
+}
+
+/*
+ * Initialize the role table by implicitly adding role 'object_r'. If
+ * the policy is a module, set object_r's scope to be SCOPE_REQ,
+ * otherwise set it to SCOPE_DECL.
+ */
+static int roles_init(policydb_t * p)
+{
+ char *key = 0;
+ int rc;
+ role_datum_t *role;
+
+ role = calloc(1, sizeof(role_datum_t));
+ if (!role) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ key = malloc(strlen(OBJECT_R) + 1);
+ if (!key) {
+ rc = -ENOMEM;
+ goto out_free_role;
+ }
+ strcpy(key, OBJECT_R);
+ rc = symtab_insert(p, SYM_ROLES, key, role,
+ (p->policy_type ==
+ POLICY_MOD ? SCOPE_REQ : SCOPE_DECL), 1,
+ &role->s.value);
+ if (rc)
+ goto out_free_key;
+ if (role->s.value != OBJECT_R_VAL) {
+ rc = -EINVAL;
+ goto out_free_role;
+ }
+ out:
+ return rc;
+
+ out_free_key:
+ free(key);
+ out_free_role:
+ free(role);
+ goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+int policydb_init(policydb_t * p)
+{
+ int i, rc;
+
+ memset(p, 0, sizeof(policydb_t));
+
+ ebitmap_init(&p->policycaps);
+
+ ebitmap_init(&p->permissive_map);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ p->sym_val_to_name[i] = NULL;
+ rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+ if (rc)
+ goto out_free_symtab;
+ }
+
+ /* initialize the module stuff */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (symtab_init(&p->scope[i], symtab_sizes[i])) {
+ goto out_free_symtab;
+ }
+ }
+ if ((p->global = avrule_block_create()) == NULL ||
+ (p->global->branch_list = avrule_decl_create(1)) == NULL) {
+ goto out_free_symtab;
+ }
+ p->decl_val_to_struct = NULL;
+
+ rc = avtab_init(&p->te_avtab);
+ if (rc)
+ goto out_free_symtab;
+
+ rc = roles_init(p);
+ if (rc)
+ goto out_free_symtab;
+
+ rc = cond_policydb_init(p);
+ if (rc)
+ goto out_free_symtab;
+ out:
+ return rc;
+
+ out_free_symtab:
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_destroy(p->symtab[i].table);
+ hashtab_destroy(p->scope[i].table);
+ }
+ avrule_block_list_destroy(p->global);
+ goto out;
+}
+
+int policydb_role_cache(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *arg)
+{
+ policydb_t *p;
+ role_datum_t *role;
+
+ role = (role_datum_t *) datum;
+ p = (policydb_t *) arg;
+
+ ebitmap_destroy(&role->cache);
+ if (type_set_expand(&role->types, &role->cache, p, 1)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int policydb_user_cache(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *arg)
+{
+ policydb_t *p;
+ user_datum_t *user;
+
+ user = (user_datum_t *) datum;
+ p = (policydb_t *) arg;
+
+ ebitmap_destroy(&user->cache);
+ if (role_set_expand(&user->roles, &user->cache, p, NULL, NULL)) {
+ return -1;
+ }
+
+ /* we do not expand user's MLS info in kernel policies because the
+ * semantic representation is not present and we do not expand user's
+ * MLS info in module policies because all of the necessary mls
+ * information is not present */
+ if (p->policy_type != POLICY_KERN && p->policy_type != POLICY_MOD) {
+ mls_range_destroy(&user->exp_range);
+ if (mls_semantic_range_expand(&user->range,
+ &user->exp_range, p, NULL)) {
+ return -1;
+ }
+
+ mls_level_destroy(&user->exp_dfltlevel);
+ if (mls_semantic_level_expand(&user->dfltlevel,
+ &user->exp_dfltlevel, p, NULL)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure. The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations. The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ common_datum_t *comdatum;
+
+ comdatum = (common_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!comdatum->s.value || comdatum->s.value > p->p_commons.nprim)
+ return -EINVAL;
+ p->p_common_val_to_name[comdatum->s.value - 1] = (char *)key;
+
+ return 0;
+}
+
+static int class_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ class_datum_t *cladatum;
+
+ cladatum = (class_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!cladatum->s.value || cladatum->s.value > p->p_classes.nprim)
+ return -EINVAL;
+ p->p_class_val_to_name[cladatum->s.value - 1] = (char *)key;
+ p->class_val_to_struct[cladatum->s.value - 1] = cladatum;
+
+ return 0;
+}
+
+static int role_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ role_datum_t *role;
+
+ role = (role_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!role->s.value || role->s.value > p->p_roles.nprim)
+ return -EINVAL;
+ p->p_role_val_to_name[role->s.value - 1] = (char *)key;
+ p->role_val_to_struct[role->s.value - 1] = role;
+
+ return 0;
+}
+
+static int type_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ type_datum_t *typdatum;
+
+ typdatum = (type_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (typdatum->primary) {
+ if (!typdatum->s.value || typdatum->s.value > p->p_types.nprim)
+ return -EINVAL;
+ p->p_type_val_to_name[typdatum->s.value - 1] = (char *)key;
+ p->type_val_to_struct[typdatum->s.value - 1] = typdatum;
+ }
+
+ return 0;
+}
+
+static int user_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ user_datum_t *usrdatum;
+
+ usrdatum = (user_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!usrdatum->s.value || usrdatum->s.value > p->p_users.nprim)
+ return -EINVAL;
+
+ p->p_user_val_to_name[usrdatum->s.value - 1] = (char *)key;
+ p->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+
+ return 0;
+}
+
+static int sens_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ level_datum_t *levdatum;
+
+ levdatum = (level_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!levdatum->isalias) {
+ if (!levdatum->level->sens ||
+ levdatum->level->sens > p->p_levels.nprim)
+ return -EINVAL;
+ p->p_sens_val_to_name[levdatum->level->sens - 1] = (char *)key;
+ }
+
+ return 0;
+}
+
+static int cat_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ cat_datum_t *catdatum;
+
+ catdatum = (cat_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!catdatum->isalias) {
+ if (!catdatum->s.value || catdatum->s.value > p->p_cats.nprim)
+ return -EINVAL;
+ p->p_cat_val_to_name[catdatum->s.value - 1] = (char *)key;
+ }
+
+ return 0;
+}
+
+static int (*index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_index, class_index, role_index, type_index, user_index,
+ cond_index_bool, sens_index, cat_index,};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.
+ */
+int policydb_index_classes(policydb_t * p)
+{
+ free(p->p_common_val_to_name);
+ p->p_common_val_to_name = (char **)
+ malloc(p->p_commons.nprim * sizeof(char *));
+ if (!p->p_common_val_to_name)
+ return -1;
+
+ if (hashtab_map(p->p_commons.table, common_index, p))
+ return -1;
+
+ free(p->class_val_to_struct);
+ p->class_val_to_struct = (class_datum_t **)
+ malloc(p->p_classes.nprim * sizeof(class_datum_t *));
+ if (!p->class_val_to_struct)
+ return -1;
+
+ free(p->p_class_val_to_name);
+ p->p_class_val_to_name = (char **)
+ malloc(p->p_classes.nprim * sizeof(char *));
+ if (!p->p_class_val_to_name)
+ return -1;
+
+ if (hashtab_map(p->p_classes.table, class_index, p))
+ return -1;
+
+ return 0;
+}
+
+int policydb_index_bools(policydb_t * p)
+{
+
+ if (cond_init_bool_indexes(p) == -1)
+ return -1;
+ p->p_bool_val_to_name = (char **)
+ malloc(p->p_bools.nprim * sizeof(char *));
+ if (!p->p_bool_val_to_name)
+ return -1;
+ if (hashtab_map(p->p_bools.table, cond_index_bool, p))
+ return -1;
+ return 0;
+}
+
+int policydb_index_decls(policydb_t * p)
+{
+ avrule_block_t *curblock;
+ avrule_decl_t *decl;
+ int num_decls = 0;
+
+ free(p->decl_val_to_struct);
+
+ for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+ for (decl = curblock->branch_list; decl != NULL;
+ decl = decl->next) {
+ num_decls++;
+ }
+ }
+
+ p->decl_val_to_struct =
+ calloc(num_decls, sizeof(*(p->decl_val_to_struct)));
+ if (!p->decl_val_to_struct) {
+ return -1;
+ }
+
+ for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+ for (decl = curblock->branch_list; decl != NULL;
+ decl = decl->next) {
+ p->decl_val_to_struct[decl->decl_id - 1] = decl;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.
+ */
+int policydb_index_others(sepol_handle_t * handle,
+ policydb_t * p, unsigned verbose)
+{
+ int i;
+
+ if (verbose) {
+ INFO(handle,
+ "security: %d users, %d roles, %d types, %d bools",
+ p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
+ p->p_bools.nprim);
+
+ if (p->mls)
+ INFO(handle, "security: %d sens, %d cats",
+ p->p_levels.nprim, p->p_cats.nprim);
+
+ INFO(handle, "security: %d classes, %d rules, %d cond rules",
+ p->p_classes.nprim, p->te_avtab.nel, p->te_cond_avtab.nel);
+ }
+#if 0
+ avtab_hash_eval(&p->te_avtab, "rules");
+ for (i = 0; i < SYM_NUM; i++)
+ hashtab_hash_eval(p->symtab[i].table, symtab_name[i]);
+#endif
+
+ free(p->role_val_to_struct);
+ p->role_val_to_struct = (role_datum_t **)
+ malloc(p->p_roles.nprim * sizeof(role_datum_t *));
+ if (!p->role_val_to_struct)
+ return -1;
+
+ free(p->user_val_to_struct);
+ p->user_val_to_struct = (user_datum_t **)
+ malloc(p->p_users.nprim * sizeof(user_datum_t *));
+ if (!p->user_val_to_struct)
+ return -1;
+
+ free(p->type_val_to_struct);
+ p->type_val_to_struct = (type_datum_t **)
+ calloc(p->p_types.nprim, sizeof(type_datum_t *));
+ if (!p->type_val_to_struct)
+ return -1;
+
+ cond_init_bool_indexes(p);
+
+ for (i = SYM_ROLES; i < SYM_NUM; i++) {
+ free(p->sym_val_to_name[i]);
+ p->sym_val_to_name[i] = NULL;
+ if (p->symtab[i].nprim) {
+ p->sym_val_to_name[i] = (char **)
+ calloc(p->symtab[i].nprim, sizeof(char *));
+ if (!p->sym_val_to_name[i])
+ return -1;
+ if (hashtab_map(p->symtab[i].table, index_f[i], p))
+ return -1;
+ }
+ }
+
+ /* This pre-expands the roles and users for context validity checking */
+ if (hashtab_map(p->p_roles.table, policydb_role_cache, p))
+ return -1;
+
+ if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ free(datum);
+ return 0;
+}
+
+static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ common_datum_t *comdatum;
+
+ if (key)
+ free(key);
+ comdatum = (common_datum_t *) datum;
+ hashtab_map(comdatum->permissions.table, perm_destroy, 0);
+ hashtab_destroy(comdatum->permissions.table);
+ free(datum);
+ return 0;
+}
+
+static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ class_datum_t *cladatum;
+ constraint_node_t *constraint, *ctemp;
+ constraint_expr_t *e, *etmp;
+
+ if (key)
+ free(key);
+ cladatum = (class_datum_t *) datum;
+ if (cladatum == NULL) {
+ return 0;
+ }
+ hashtab_map(cladatum->permissions.table, perm_destroy, 0);
+ hashtab_destroy(cladatum->permissions.table);
+ constraint = cladatum->constraints;
+ while (constraint) {
+ e = constraint->expr;
+ while (e) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ free(ctemp);
+ }
+
+ constraint = cladatum->validatetrans;
+ while (constraint) {
+ e = constraint->expr;
+ while (e) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ free(ctemp);
+ }
+
+ if (cladatum->comkey)
+ free(cladatum->comkey);
+ free(datum);
+ return 0;
+}
+
+static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ role_datum_destroy((role_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ type_datum_destroy((type_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ user_datum_destroy((user_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ level_datum_t *levdatum;
+
+ if (key)
+ free(key);
+ levdatum = (level_datum_t *) datum;
+ mls_level_destroy(levdatum->level);
+ free(levdatum->level);
+ level_datum_destroy(levdatum);
+ free(levdatum);
+ return 0;
+}
+
+static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ cat_datum_destroy((cat_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
+ cond_destroy_bool, sens_destroy, cat_destroy,};
+
+void ocontext_selinux_free(ocontext_t **ocontexts)
+{
+ ocontext_t *c, *ctmp;
+ int i;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ c = ocontexts[i];
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ context_destroy(&ctmp->context[1]);
+ if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF
+ || i == OCON_FSUSE)
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ }
+}
+
+void ocontext_xen_free(ocontext_t **ocontexts)
+{
+ ocontext_t *c, *ctmp;
+ int i;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ c = ocontexts[i];
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ context_destroy(&ctmp->context[1]);
+ if (i == OCON_ISID)
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ }
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(policydb_t * p)
+{
+ ocontext_t *c, *ctmp;
+ genfs_t *g, *gtmp;
+ unsigned int i;
+ role_allow_t *ra, *lra = NULL;
+ role_trans_t *tr, *ltr = NULL;
+ range_trans_t *rt, *lrt = NULL;
+ filename_trans_t *ft, *nft;
+
+ if (!p)
+ return;
+
+ ebitmap_destroy(&p->policycaps);
+
+ ebitmap_destroy(&p->permissive_map);
+
+ symtabs_destroy(p->symtab);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ if (p->sym_val_to_name[i])
+ free(p->sym_val_to_name[i]);
+ }
+
+ if (p->class_val_to_struct)
+ free(p->class_val_to_struct);
+ if (p->role_val_to_struct)
+ free(p->role_val_to_struct);
+ if (p->user_val_to_struct)
+ free(p->user_val_to_struct);
+ if (p->type_val_to_struct)
+ free(p->type_val_to_struct);
+ free(p->decl_val_to_struct);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_map(p->scope[i].table, scope_destroy, 0);
+ hashtab_destroy(p->scope[i].table);
+ }
+ avrule_block_list_destroy(p->global);
+ free(p->name);
+ free(p->version);
+
+ avtab_destroy(&p->te_avtab);
+
+ if (p->target_platform == SEPOL_TARGET_SELINUX)
+ ocontext_selinux_free(p->ocontexts);
+ else if (p->target_platform == SEPOL_TARGET_XEN)
+ ocontext_xen_free(p->ocontexts);
+
+ g = p->genfs;
+ while (g) {
+ free(g->fstype);
+ c = g->head;
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ gtmp = g;
+ g = g->next;
+ free(gtmp);
+ }
+ cond_policydb_destroy(p);
+
+ for (tr = p->role_tr; tr; tr = tr->next) {
+ if (ltr)
+ free(ltr);
+ ltr = tr;
+ }
+ if (ltr)
+ free(ltr);
+
+ ft = p->filename_trans;
+ while (ft) {
+ nft = ft->next;
+ free(ft->name);
+ free(ft);
+ ft = nft;
+ }
+
+ for (ra = p->role_allow; ra; ra = ra->next) {
+ if (lra)
+ free(lra);
+ lra = ra;
+ }
+ if (lra)
+ free(lra);
+
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ lrt = rt;
+ }
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+
+ if (p->type_attr_map) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_destroy(&p->type_attr_map[i]);
+ }
+ free(p->type_attr_map);
+ }
+
+ if (p->attr_type_map) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_destroy(&p->attr_type_map[i]);
+ }
+ free(p->attr_type_map);
+ }
+
+ return;
+}
+
+void symtabs_destroy(symtab_t * symtab)
+{
+ int i;
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_map(symtab[i].table, destroy_f[i], 0);
+ hashtab_destroy(symtab[i].table);
+ }
+}
+
+int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ scope_datum_t *cur = (scope_datum_t *) datum;
+ free(key);
+ if (cur != NULL) {
+ free(cur->decl_ids);
+ }
+ free(cur);
+ return 0;
+}
+
+hashtab_destroy_func_t get_symtab_destroy_func(int sym_num)
+{
+ if (sym_num < 0 || sym_num >= SYM_NUM) {
+ return NULL;
+ }
+ return (hashtab_destroy_func_t) destroy_f[sym_num];
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(policydb_t * p, sidtab_t * s)
+{
+ ocontext_t *head, *c;
+
+ if (sepol_sidtab_init(s)) {
+ ERR(NULL, "out of memory on SID table init");
+ return -1;
+ }
+
+ head = p->ocontexts[OCON_ISID];
+ for (c = head; c; c = c->next) {
+ if (!c->context[0].user) {
+ ERR(NULL, "SID %s was never defined", c->u.name);
+ return -1;
+ }
+ if (sepol_sidtab_insert(s, c->sid[0], &c->context[0])) {
+ ERR(NULL, "unable to load initial SID %s", c->u.name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Declare a symbol for a certain avrule_block context. Insert it
+ * into a symbol table for a policy. This function will handle
+ * inserting the appropriate scope information in addition to
+ * inserting the symbol into the hash table.
+ *
+ * arguments:
+ * policydb_t *pol module policy to modify
+ * uint32_t sym the symbole table for insertion (SYM_*)
+ * hashtab_key_t key the key for the symbol - not cloned
+ * hashtab_datum_t data the data for the symbol - not cloned
+ * scope scope of this symbol, either SCOPE_REQ or SCOPE_DECL
+ * avrule_decl_id identifier for this symbol's encapsulating declaration
+ * value (out) assigned value to the symbol (if value is not NULL)
+ *
+ * returns:
+ * 0 success
+ * 1 success, but symbol already existed as a requirement
+ * (datum was not inserted and needs to be free()d)
+ * -1 general error
+ * -2 scope conflicted
+ * -ENOMEM memory error
+ * error codes from hashtab_insert
+ */
+int symtab_insert(policydb_t * pol, uint32_t sym,
+ hashtab_key_t key, hashtab_datum_t datum,
+ uint32_t scope, uint32_t avrule_decl_id, uint32_t * value)
+{
+ int rc, retval = 0;
+ unsigned int i;
+ scope_datum_t *scope_datum;
+
+ /* check if the symbol is already there. multiple
+ * declarations of non-roles/non-users are illegal, but
+ * multiple requires are allowed. */
+
+ /* FIX ME - the failures after the hashtab_insert will leave
+ * the policy in a inconsistent state. */
+ rc = hashtab_insert(pol->symtab[sym].table, key, datum);
+ if (rc == SEPOL_OK) {
+ /* if no value is passed in the symbol is not primary
+ * (i.e. aliases) */
+ if (value)
+ *value = ++pol->symtab[sym].nprim;
+ } else if (rc == SEPOL_EEXIST) {
+ retval = 1; /* symbol not added -- need to free() later */
+ } else {
+ return rc;
+ }
+
+ /* get existing scope information; if there is not one then
+ * create it */
+ scope_datum =
+ (scope_datum_t *) hashtab_search(pol->scope[sym].table, key);
+ if (scope_datum == NULL) {
+ hashtab_key_t key2 = strdup((char *)key);
+ if (!key2)
+ return -ENOMEM;
+ if ((scope_datum = malloc(sizeof(*scope_datum))) == NULL) {
+ free(key2);
+ return -ENOMEM;
+ }
+ scope_datum->scope = scope;
+ scope_datum->decl_ids = NULL;
+ scope_datum->decl_ids_len = 0;
+ if ((rc =
+ hashtab_insert(pol->scope[sym].table, key2,
+ scope_datum)) != 0) {
+ free(key2);
+ free(scope_datum);
+ return rc;
+ }
+ } else if (scope_datum->scope == SCOPE_DECL && scope == SCOPE_DECL) {
+ /* disallow multiple declarations for non-roles/users */
+ if (sym != SYM_ROLES && sym != SYM_USERS) {
+ return -2;
+ }
+ /* Further confine that a role attribute can't have the same
+ * name as another regular role, and a role attribute can't
+ * be declared more than once. */
+ if (sym == SYM_ROLES) {
+ role_datum_t *base_role;
+ role_datum_t *cur_role = (role_datum_t *)datum;
+
+ base_role = (role_datum_t *)
+ hashtab_search(pol->symtab[sym].table,
+ key);
+ assert(base_role != NULL);
+
+ if (!((base_role->flavor == ROLE_ROLE) &&
+ (cur_role->flavor == ROLE_ROLE))) {
+ /* Only regular roles are allowed to have
+ * multiple declarations. */
+ return -2;
+ }
+ }
+ } else if (scope_datum->scope == SCOPE_REQ && scope == SCOPE_DECL) {
+ scope_datum->scope = SCOPE_DECL;
+ } else if (scope_datum->scope != scope) {
+ /* This only happens in DECL then REQUIRE case, which is handled by caller */
+ return -2;
+ }
+
+ /* search through the pre-existing list to avoid adding duplicates */
+ for (i = 0; i < scope_datum->decl_ids_len; i++) {
+ if (scope_datum->decl_ids[i] == avrule_decl_id) {
+ /* already there, so don't modify its scope */
+ return retval;
+ }
+ }
+
+ if (add_i_to_a(avrule_decl_id,
+ &scope_datum->decl_ids_len,
+ &scope_datum->decl_ids) == -1) {
+ return -ENOMEM;
+ }
+
+ return retval;
+}
+
+int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b)
+{
+ type_set_init(dst);
+
+ if (ebitmap_or(&dst->types, &a->types, &b->types)) {
+ return -1;
+ }
+ if (ebitmap_or(&dst->negset, &a->negset, &b->negset)) {
+ return -1;
+ }
+
+ dst->flags |= a->flags;
+ dst->flags |= b->flags;
+
+ return 0;
+}
+
+int type_set_cpy(type_set_t * dst, type_set_t * src)
+{
+ type_set_init(dst);
+
+ dst->flags = src->flags;
+ if (ebitmap_cpy(&dst->types, &src->types))
+ return -1;
+ if (ebitmap_cpy(&dst->negset, &src->negset))
+ return -1;
+
+ return 0;
+}
+
+int type_set_or_eq(type_set_t * dst, type_set_t * other)
+{
+ int ret;
+ type_set_t tmp;
+
+ if (type_set_or(&tmp, dst, other))
+ return -1;
+ type_set_destroy(dst);
+ ret = type_set_cpy(dst, &tmp);
+ type_set_destroy(&tmp);
+
+ return ret;
+}
+
+int role_set_get_role(role_set_t * x, uint32_t role)
+{
+ if (x->flags & ROLE_STAR)
+ return 1;
+
+ if (ebitmap_get_bit(&x->roles, role - 1)) {
+ if (x->flags & ROLE_COMP)
+ return 0;
+ else
+ return 1;
+ } else {
+ if (x->flags & ROLE_COMP)
+ return 1;
+ else
+ return 0;
+ }
+}
+
+/***********************************************************************/
+/* everything below is for policy reads */
+
+/* The following are read functions for module structures */
+
+static int role_set_read(role_set_t * r, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ if (ebitmap_read(&r->roles, fp))
+ return -1;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ r->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+static int type_set_read(type_set_t * t, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ if (ebitmap_read(&t->types, fp))
+ return -1;
+ if (ebitmap_read(&t->negset, fp))
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ t->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+ uint32_t buf[2], items;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto out;
+
+ items = le32_to_cpu(buf[0]);
+ if (items > ARRAY_SIZE(buf)) {
+ ERR(fp->handle, "range overflow");
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * items);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated range");
+ goto out;
+ }
+ r->level[0].sens = le32_to_cpu(buf[0]);
+ if (items > 1)
+ r->level[1].sens = le32_to_cpu(buf[1]);
+ else
+ r->level[1].sens = r->level[0].sens;
+
+ rc = ebitmap_read(&r->level[0].cat, fp);
+ if (rc) {
+ ERR(fp->handle, "error reading low categories");
+ goto out;
+ }
+ if (items > 1) {
+ rc = ebitmap_read(&r->level[1].cat, fp);
+ if (rc) {
+ ERR(fp->handle, "error reading high categories");
+ goto bad_high;
+ }
+ } else {
+ rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+ if (rc) {
+ ERR(fp->handle, "out of memory");
+ goto bad_high;
+ }
+ }
+
+ rc = 0;
+ out:
+ return rc;
+ bad_high:
+ ebitmap_destroy(&r->level[0].cat);
+ goto out;
+}
+
+/*
+ * Read a semantic MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_semantic_level_helper(mls_semantic_level_t * l,
+ struct policy_file *fp)
+{
+ uint32_t buf[2], ncat;
+ unsigned int i;
+ mls_semantic_cat_t *cat;
+ int rc;
+
+ mls_semantic_level_init(l);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated level");
+ goto bad;
+ }
+ l->sens = le32_to_cpu(buf[0]);
+
+ ncat = le32_to_cpu(buf[1]);
+ for (i = 0; i < ncat; i++) {
+ cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!cat) {
+ ERR(fp->handle, "out of memory");
+ goto bad;
+ }
+
+ mls_semantic_cat_init(cat);
+ cat->next = l->cat;
+ l->cat = cat;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(fp->handle, "error reading level categories");
+ goto bad;
+ }
+ cat->low = le32_to_cpu(buf[0]);
+ cat->high = le32_to_cpu(buf[1]);
+ }
+
+ return 0;
+
+ bad:
+ return -EINVAL;
+}
+
+/*
+ * Read a semantic MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_semantic_range_helper(mls_semantic_range_t * r,
+ struct policy_file *fp)
+{
+ int rc;
+
+ rc = mls_read_semantic_level_helper(&r->level[0], fp);
+ if (rc)
+ return rc;
+
+ rc = mls_read_semantic_level_helper(&r->level[1], fp);
+
+ return rc;
+}
+
+static int mls_level_to_semantic(mls_level_t * l, mls_semantic_level_t * sl)
+{
+ unsigned int i;
+ ebitmap_node_t *cnode;
+ mls_semantic_cat_t *open_cat = NULL;
+
+ mls_semantic_level_init(sl);
+ sl->sens = l->sens;
+ ebitmap_for_each_bit(&l->cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (open_cat)
+ continue;
+ open_cat = (mls_semantic_cat_t *)
+ malloc(sizeof(mls_semantic_cat_t));
+ if (!open_cat)
+ return -1;
+
+ mls_semantic_cat_init(open_cat);
+ open_cat->low = i + 1;
+ open_cat->next = sl->cat;
+ sl->cat = open_cat;
+ } else {
+ if (!open_cat)
+ continue;
+ open_cat->high = i;
+ open_cat = NULL;
+ }
+ }
+ if (open_cat)
+ open_cat->high = i;
+
+ return 0;
+}
+
+static int mls_range_to_semantic(mls_range_t * r, mls_semantic_range_t * sr)
+{
+ if (mls_level_to_semantic(&r->level[0], &sr->level[0]))
+ return -1;
+
+ if (mls_level_to_semantic(&r->level[1], &sr->level[1]))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(context_struct_t * c,
+ policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[3];
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0) {
+ ERR(fp->handle, "context truncated");
+ return -1;
+ }
+ c->user = le32_to_cpu(buf[0]);
+ c->role = le32_to_cpu(buf[1]);
+ c->type = le32_to_cpu(buf[2]);
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS)) {
+ if (mls_read_range_helper(&c->range, fp)) {
+ ERR(fp->handle, "error reading MLS range "
+ "of context");
+ return -1;
+ }
+ }
+
+ if (!policydb_context_isvalid(p, c)) {
+ ERR(fp->handle, "invalid security context");
+ context_destroy(c);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ perm_datum_t *perdatum;
+ uint32_t buf[2];
+ size_t len;
+ int rc;
+
+ perdatum = calloc(1, sizeof(perm_datum_t));
+ if (!perdatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ perdatum->s.value = le32_to_cpu(buf[1]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, perdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ perm_destroy(key, perdatum, NULL);
+ return -1;
+}
+
+static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ common_datum_t *comdatum;
+ uint32_t buf[4];
+ size_t len, nel;
+ unsigned int i;
+ int rc;
+
+ comdatum = calloc(1, sizeof(common_datum_t));
+ if (!comdatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ comdatum->s.value = le32_to_cpu(buf[1]);
+
+ if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
+ goto bad;
+ comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+ nel = le32_to_cpu(buf[3]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ for (i = 0; i < nel; i++) {
+ if (perm_read(p, comdatum->permissions.table, fp))
+ goto bad;
+ }
+
+ if (hashtab_insert(h, key, comdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ common_destroy(key, comdatum, NULL);
+ return -1;
+}
+
+static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep,
+ unsigned int ncons,
+ int allowxtarget, struct policy_file *fp)
+{
+ constraint_node_t *c, *lc;
+ constraint_expr_t *e, *le;
+ uint32_t buf[3];
+ size_t nexpr;
+ unsigned int i, j;
+ int rc, depth;
+
+ lc = NULL;
+ for (i = 0; i < ncons; i++) {
+ c = calloc(1, sizeof(constraint_node_t));
+ if (!c)
+ return -1;
+
+ if (lc)
+ lc->next = c;
+ else
+ *nodep = c;
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ return -1;
+ c->permissions = le32_to_cpu(buf[0]);
+ nexpr = le32_to_cpu(buf[1]);
+ le = NULL;
+ depth = -1;
+ for (j = 0; j < nexpr; j++) {
+ e = malloc(sizeof(constraint_expr_t));
+ if (!e)
+ return -1;
+ if (constraint_expr_init(e) == -1) {
+ free(e);
+ return -1;
+ }
+ if (le) {
+ le->next = e;
+ } else {
+ c->expr = e;
+ }
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+ if (rc < 0)
+ return -1;
+ e->expr_type = le32_to_cpu(buf[0]);
+ e->attr = le32_to_cpu(buf[1]);
+ e->op = le32_to_cpu(buf[2]);
+
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ if (depth < 0)
+ return -1;
+ break;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ if (depth < 1)
+ return -1;
+ depth--;
+ break;
+ case CEXPR_ATTR:
+ if (depth == (CEXPR_MAXDEPTH - 1))
+ return -1;
+ depth++;
+ break;
+ case CEXPR_NAMES:
+ if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+ return -1;
+ if (depth == (CEXPR_MAXDEPTH - 1))
+ return -1;
+ depth++;
+ if (ebitmap_read(&e->names, fp))
+ return -1;
+ if (p->policy_type != POLICY_KERN &&
+ type_set_read(e->type_names, fp))
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ le = e;
+ }
+ if (depth != 0)
+ return -1;
+ lc = c;
+ }
+
+ return 0;
+}
+
+static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ class_datum_t *cladatum;
+ uint32_t buf[6];
+ size_t len, len2, ncons, nel;
+ unsigned int i;
+ int rc;
+
+ cladatum = (class_datum_t *) calloc(1, sizeof(class_datum_t));
+ if (!cladatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 6);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ len2 = le32_to_cpu(buf[1]);
+ cladatum->s.value = le32_to_cpu(buf[2]);
+
+ if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
+ goto bad;
+ cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+ nel = le32_to_cpu(buf[4]);
+
+ ncons = le32_to_cpu(buf[5]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (len2) {
+ cladatum->comkey = malloc(len2 + 1);
+ if (!cladatum->comkey)
+ goto bad;
+ rc = next_entry(cladatum->comkey, fp, len2);
+ if (rc < 0)
+ goto bad;
+ cladatum->comkey[len2] = 0;
+
+ cladatum->comdatum = hashtab_search(p->p_commons.table,
+ cladatum->comkey);
+ if (!cladatum->comdatum) {
+ ERR(fp->handle, "unknown common %s", cladatum->comkey);
+ goto bad;
+ }
+ }
+ for (i = 0; i < nel; i++) {
+ if (perm_read(p, cladatum->permissions.table, fp))
+ goto bad;
+ }
+
+ if (read_cons_helper(p, &cladatum->constraints, ncons, 0, fp))
+ goto bad;
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+ /* grab the validatetrans rules */
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ ncons = le32_to_cpu(buf[0]);
+ if (read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp))
+ goto bad;
+ }
+
+ if (hashtab_insert(h, key, cladatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ class_destroy(key, cladatum, NULL);
+ return -1;
+}
+
+static int role_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ role_datum_t *role;
+ uint32_t buf[3];
+ size_t len;
+ int rc, to_read = 2;
+
+ role = calloc(1, sizeof(role_datum_t));
+ if (!role)
+ return -1;
+
+ if (policydb_has_boundary_feature(p))
+ to_read = 3;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ role->s.value = le32_to_cpu(buf[1]);
+ if (policydb_has_boundary_feature(p))
+ role->bounds = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (ebitmap_read(&role->dominates, fp))
+ goto bad;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&role->types.types, fp))
+ goto bad;
+ } else {
+ if (type_set_read(&role->types, fp))
+ goto bad;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+
+ role->flavor = le32_to_cpu(buf[0]);
+
+ if (ebitmap_read(&role->roles, fp))
+ goto bad;
+ }
+
+ if (strcmp(key, OBJECT_R) == 0) {
+ if (role->s.value != OBJECT_R_VAL) {
+ ERR(fp->handle, "role %s has wrong value %d",
+ OBJECT_R, role->s.value);
+ role_destroy(key, role, NULL);
+ return -1;
+ }
+ role_destroy(key, role, NULL);
+ return 0;
+ }
+
+ if (hashtab_insert(h, key, role))
+ goto bad;
+
+ return 0;
+
+ bad:
+ role_destroy(key, role, NULL);
+ return -1;
+}
+
+static int type_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ type_datum_t *typdatum;
+ uint32_t buf[5];
+ size_t len;
+ int rc, to_read;
+ int pos = 0;
+
+ typdatum = calloc(1, sizeof(type_datum_t));
+ if (!typdatum)
+ return -1;
+
+ if (policydb_has_boundary_feature(p)) {
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS)
+ to_read = 5;
+ else
+ to_read = 4;
+ }
+ else if (p->policy_type == POLICY_KERN)
+ to_read = 3;
+ else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ to_read = 5;
+ else
+ to_read = 4;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[pos]);
+ typdatum->s.value = le32_to_cpu(buf[++pos]);
+ if (policydb_has_boundary_feature(p)) {
+ uint32_t properties;
+
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+ typdatum->primary = le32_to_cpu(buf[++pos]);
+ properties = le32_to_cpu(buf[++pos]);
+ }
+ else {
+ properties = le32_to_cpu(buf[++pos]);
+
+ if (properties & TYPEDATUM_PROPERTY_PRIMARY)
+ typdatum->primary = 1;
+ }
+
+ if (properties & TYPEDATUM_PROPERTY_ATTRIBUTE)
+ typdatum->flavor = TYPE_ATTRIB;
+ if (properties & TYPEDATUM_PROPERTY_ALIAS
+ && p->policy_type != POLICY_KERN)
+ typdatum->flavor = TYPE_ALIAS;
+ if (properties & TYPEDATUM_PROPERTY_PERMISSIVE
+ && p->policy_type != POLICY_KERN)
+ typdatum->flags |= TYPE_FLAGS_PERMISSIVE;
+
+ typdatum->bounds = le32_to_cpu(buf[++pos]);
+ } else {
+ typdatum->primary = le32_to_cpu(buf[++pos]);
+ if (p->policy_type != POLICY_KERN) {
+ typdatum->flavor = le32_to_cpu(buf[++pos]);
+ if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ typdatum->flags = le32_to_cpu(buf[++pos]);
+ }
+ }
+
+ if (p->policy_type != POLICY_KERN) {
+ if (ebitmap_read(&typdatum->types, fp))
+ goto bad;
+ }
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, typdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ type_destroy(key, typdatum, NULL);
+ return -1;
+}
+
+int role_trans_read(policydb_t *p, struct policy_file *fp)
+{
+ role_trans_t **t = &p->role_tr;
+ unsigned int i;
+ uint32_t buf[3], nel;
+ role_trans_t *tr, *ltr;
+ int rc;
+ int new_roletr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ ltr = NULL;
+ for (i = 0; i < nel; i++) {
+ tr = calloc(1, sizeof(struct role_trans));
+ if (!tr) {
+ return -1;
+ }
+ if (ltr) {
+ ltr->next = tr;
+ } else {
+ *t = tr;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ return -1;
+ tr->role = le32_to_cpu(buf[0]);
+ tr->type = le32_to_cpu(buf[1]);
+ tr->new_role = le32_to_cpu(buf[2]);
+ if (new_roletr) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ tr->tclass = le32_to_cpu(buf[0]);
+ } else
+ tr->tclass = SECCLASS_PROCESS;
+ ltr = tr;
+ }
+ return 0;
+}
+
+int role_allow_read(role_allow_t ** r, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[2], nel;
+ role_allow_t *ra, *lra;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lra = NULL;
+ for (i = 0; i < nel; i++) {
+ ra = calloc(1, sizeof(struct role_allow));
+ if (!ra) {
+ return -1;
+ }
+ if (lra) {
+ lra->next = ra;
+ } else {
+ *r = ra;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ ra->role = le32_to_cpu(buf[0]);
+ ra->new_role = le32_to_cpu(buf[1]);
+ lra = ra;
+ }
+ return 0;
+}
+
+int filename_trans_read(filename_trans_t **t, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[4], nel, len;
+ filename_trans_t *ft, *lft;
+ int rc;
+ char *name;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+
+ lft = NULL;
+ for (i = 0; i < nel; i++) {
+ ft = calloc(1, sizeof(struct filename_trans));
+ if (!ft)
+ return -1;
+ if (lft)
+ lft->next = ft;
+ else
+ *t = ft;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ len = le32_to_cpu(buf[0]);
+
+ name = calloc(len, sizeof(*name));
+ if (!name)
+ return -1;
+
+ ft->name = name;
+
+ rc = next_entry(name, fp, len);
+ if (rc < 0)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+ if (rc < 0)
+ return -1;
+
+ ft->stype = le32_to_cpu(buf[0]);
+ ft->ttype = le32_to_cpu(buf[1]);
+ ft->tclass = le32_to_cpu(buf[2]);
+ ft->otype = le32_to_cpu(buf[3]);
+ }
+ return 0;
+}
+
+static int ocontext_read_xen(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel;
+ ocontext_t *l, *c;
+ uint32_t buf[8];
+ int rc;
+
+ for (i = 0; i < info->ocon_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ l = NULL;
+ for (j = 0; j < nel; j++) {
+ c = calloc(1, sizeof(ocontext_t));
+ if (!c)
+ return -1;
+ if (l)
+ l->next = c;
+ else
+ p->ocontexts[i] = c;
+ l = c;
+ switch (i) {
+ case OCON_XEN_ISID:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->sid[0] = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_PIRQ:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->u.pirq = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_IOPORT:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.ioport.low_ioport = le32_to_cpu(buf[0]);
+ c->u.ioport.high_ioport = le32_to_cpu(buf[1]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_IOMEM:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.iomem.low_iomem = le32_to_cpu(buf[0]);
+ c->u.iomem.high_iomem = le32_to_cpu(buf[1]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->u.device = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ default:
+ /* should never get here */
+ ERR(fp->handle, "Unknown Xen ocontext");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+static int ocontext_read_selinux(struct policydb_compat_info *info,
+ policydb_t * p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, len;
+ ocontext_t *l, *c;
+ uint32_t buf[8];
+ int rc;
+
+ for (i = 0; i < info->ocon_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ l = NULL;
+ for (j = 0; j < nel; j++) {
+ c = calloc(1, sizeof(ocontext_t));
+ if (!c) {
+ return -1;
+ }
+ if (l) {
+ l->next = c;
+ } else {
+ p->ocontexts[i] = c;
+ }
+ l = c;
+ switch (i) {
+ case OCON_ISID:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->sid[0] = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_FS:
+ case OCON_NETIF:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ len = le32_to_cpu(buf[0]);
+ c->u.name = malloc(len + 1);
+ if (!c->u.name)
+ return -1;
+ rc = next_entry(c->u.name, fp, len);
+ if (rc < 0)
+ return -1;
+ c->u.name[len] = 0;
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ if (context_read_and_validate
+ (&c->context[1], p, fp))
+ return -1;
+ break;
+ case OCON_PORT:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ return -1;
+ c->u.port.protocol = le32_to_cpu(buf[0]);
+ c->u.port.low_port = le32_to_cpu(buf[1]);
+ c->u.port.high_port = le32_to_cpu(buf[2]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_NODE:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.node.addr = buf[0]; /* network order */
+ c->u.node.mask = buf[1]; /* network order */
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_FSUSE:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->v.behavior = le32_to_cpu(buf[0]);
+ len = le32_to_cpu(buf[1]);
+ c->u.name = malloc(len + 1);
+ if (!c->u.name)
+ return -1;
+ rc = next_entry(c->u.name, fp, len);
+ if (rc < 0)
+ return -1;
+ c->u.name[len] = 0;
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_NODE6:{
+ int k;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 8);
+ if (rc < 0)
+ return -1;
+ for (k = 0; k < 4; k++)
+ /* network order */
+ c->u.node6.addr[k] = buf[k];
+ for (k = 0; k < 4; k++)
+ /* network order */
+ c->u.node6.mask[k] = buf[k + 4];
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ }
+ default:{
+ ERR(fp->handle, "Unknown SELinux ocontext");
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_read(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ int rc = -1;
+ switch (p->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_read_selinux(info, p, fp);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_read_xen(info, p, fp);
+ break;
+ default:
+ ERR(fp->handle, "Unknown target");
+ }
+ return rc;
+}
+
+static int genfs_read(policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ size_t nel, nel2, len, len2;
+ genfs_t *genfs_p, *newgenfs, *genfs;
+ unsigned int i, j;
+ ocontext_t *l, *c, *newc = NULL;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ genfs_p = NULL;
+ for (i = 0; i < nel; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+ newgenfs = calloc(1, sizeof(genfs_t));
+ if (!newgenfs)
+ goto bad;
+ newgenfs->fstype = malloc(len + 1);
+ if (!newgenfs->fstype) {
+ free(newgenfs);
+ goto bad;
+ }
+ rc = next_entry(newgenfs->fstype, fp, len);
+ if (rc < 0) {
+ free(newgenfs->fstype);
+ free(newgenfs);
+ goto bad;
+ }
+ newgenfs->fstype[len] = 0;
+ for (genfs_p = NULL, genfs = p->genfs; genfs;
+ genfs_p = genfs, genfs = genfs->next) {
+ if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+ ERR(fp->handle, "dup genfs fstype %s",
+ newgenfs->fstype);
+ free(newgenfs->fstype);
+ free(newgenfs);
+ goto bad;
+ }
+ if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+ break;
+ }
+ newgenfs->next = genfs;
+ if (genfs_p)
+ genfs_p->next = newgenfs;
+ else
+ p->genfs = newgenfs;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ nel2 = le32_to_cpu(buf[0]);
+ for (j = 0; j < nel2; j++) {
+ newc = calloc(1, sizeof(ocontext_t));
+ if (!newc) {
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+ newc->u.name = malloc(len + 1);
+ if (!newc->u.name) {
+ goto bad;
+ }
+ rc = next_entry(newc->u.name, fp, len);
+ if (rc < 0)
+ goto bad;
+ newc->u.name[len] = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ newc->v.sclass = le32_to_cpu(buf[0]);
+ if (context_read_and_validate(&newc->context[0], p, fp))
+ goto bad;
+ for (l = NULL, c = newgenfs->head; c;
+ l = c, c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name) &&
+ (!c->v.sclass || !newc->v.sclass ||
+ newc->v.sclass == c->v.sclass)) {
+ ERR(fp->handle, "dup genfs entry "
+ "(%s,%s)", newgenfs->fstype,
+ c->u.name);
+ goto bad;
+ }
+ len = strlen(newc->u.name);
+ len2 = strlen(c->u.name);
+ if (len > len2)
+ break;
+ }
+ newc->next = c;
+ if (l)
+ l->next = newc;
+ else
+ newgenfs->head = newc;
+ }
+ }
+
+ return 0;
+
+ bad:
+ if (newc) {
+ context_destroy(&newc->context[0]);
+ context_destroy(&newc->context[1]);
+ free(newc->u.name);
+ free(newc);
+ }
+ return -1;
+}
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(mls_level_t * lp, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ mls_level_init(lp);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated level");
+ goto bad;
+ }
+ lp->sens = le32_to_cpu(buf[0]);
+
+ if (ebitmap_read(&lp->cat, fp)) {
+ ERR(fp->handle, "error reading level categories");
+ goto bad;
+ }
+ return 0;
+
+ bad:
+ return -EINVAL;
+}
+
+static int user_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ user_datum_t *usrdatum;
+ uint32_t buf[3];
+ size_t len;
+ int rc, to_read = 2;
+
+ usrdatum = calloc(1, sizeof(user_datum_t));
+ if (!usrdatum)
+ return -1;
+
+ if (policydb_has_boundary_feature(p))
+ to_read = 3;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ usrdatum->s.value = le32_to_cpu(buf[1]);
+ if (policydb_has_boundary_feature(p))
+ usrdatum->bounds = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&usrdatum->roles.roles, fp))
+ goto bad;
+ } else {
+ if (role_set_read(&usrdatum->roles, fp))
+ goto bad;
+ }
+
+ /* users were not allowed in mls modules before version
+ * MOD_POLICYDB_VERSION_MLS_USERS, but they could have been
+ * required - the mls fields will be empty. user declarations in
+ * non-mls modules will also have empty mls fields */
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_MOD
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)) {
+ if (mls_read_range_helper(&usrdatum->exp_range, fp))
+ goto bad;
+ if (mls_read_level(&usrdatum->exp_dfltlevel, fp))
+ goto bad;
+ if (p->policy_type != POLICY_KERN) {
+ if (mls_range_to_semantic(&usrdatum->exp_range,
+ &usrdatum->range))
+ goto bad;
+ if (mls_level_to_semantic(&usrdatum->exp_dfltlevel,
+ &usrdatum->dfltlevel))
+ goto bad;
+ }
+ } else if ((p->policy_type == POLICY_MOD
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)) {
+ if (mls_read_semantic_range_helper(&usrdatum->range, fp))
+ goto bad;
+ if (mls_read_semantic_level_helper(&usrdatum->dfltlevel, fp))
+ goto bad;
+ }
+
+ if (hashtab_insert(h, key, usrdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ user_destroy(key, usrdatum, NULL);
+ return -1;
+}
+
+static int sens_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ level_datum_t *levdatum;
+ uint32_t buf[2], len;
+ int rc;
+
+ levdatum = malloc(sizeof(level_datum_t));
+ if (!levdatum)
+ return -1;
+ level_datum_init(levdatum);
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ levdatum->isalias = le32_to_cpu(buf[1]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ levdatum->level = malloc(sizeof(mls_level_t));
+ if (!levdatum->level || mls_read_level(levdatum->level, fp))
+ goto bad;
+
+ if (hashtab_insert(h, key, levdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ sens_destroy(key, levdatum, NULL);
+ return -1;
+}
+
+static int cat_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ cat_datum_t *catdatum;
+ uint32_t buf[3], len;
+ int rc;
+
+ catdatum = malloc(sizeof(cat_datum_t));
+ if (!catdatum)
+ return -1;
+ cat_datum_init(catdatum);
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ catdatum->s.value = le32_to_cpu(buf[1]);
+ catdatum->isalias = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, catdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ cat_destroy(key, catdatum, NULL);
+ return -1;
+}
+
+static int (*read_f[SYM_NUM]) (policydb_t * p, hashtab_t h,
+ struct policy_file * fp) = {
+common_read, class_read, role_read, type_read, user_read,
+ cond_read_bool, sens_read, cat_read,};
+
+/************** module reading functions below **************/
+
+static avrule_t *avrule_read(policydb_t * p
+ __attribute__ ((unused)), struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[2], len;
+ class_perm_node_t *cur, *tail = NULL;
+ avrule_t *avrule;
+ int rc;
+
+ avrule = (avrule_t *) malloc(sizeof(avrule_t));
+ if (!avrule)
+ return NULL;
+
+ avrule_init(avrule);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+
+ (avrule)->specified = le32_to_cpu(buf[0]);
+ (avrule)->flags = le32_to_cpu(buf[1]);
+
+ if (type_set_read(&avrule->stypes, fp))
+ goto bad;
+
+ if (type_set_read(&avrule->ttypes, fp))
+ goto bad;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ cur = (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+ if (!cur)
+ goto bad;
+ class_perm_node_init(cur);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ free(cur);
+ goto bad;
+ }
+
+ cur->class = le32_to_cpu(buf[0]);
+ cur->data = le32_to_cpu(buf[1]);
+
+ if (!tail) {
+ avrule->perms = cur;
+ } else {
+ tail->next = cur;
+ }
+ tail = cur;
+ }
+
+ return avrule;
+ bad:
+ if (avrule) {
+ avrule_destroy(avrule);
+ free(avrule);
+ }
+ return NULL;
+}
+
+static int range_read(policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[2], nel;
+ range_trans_t *rt, *lrt;
+ range_trans_rule_t *rtr, *lrtr = NULL;
+ unsigned int i;
+ int new_rangetr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lrt = NULL;
+ for (i = 0; i < nel; i++) {
+ rt = calloc(1, sizeof(range_trans_t));
+ if (!rt)
+ return -1;
+ if (lrt)
+ lrt->next = rt;
+ else
+ p->range_tr = rt;
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ return -1;
+ rt->source_type = le32_to_cpu(buf[0]);
+ rt->target_type = le32_to_cpu(buf[1]);
+ if (new_rangetr) {
+ rc = next_entry(buf, fp, (sizeof(uint32_t)));
+ if (rc < 0)
+ return -1;
+ rt->target_class = le32_to_cpu(buf[0]);
+ } else
+ rt->target_class = SECCLASS_PROCESS;
+ if (mls_read_range_helper(&rt->target_range, fp))
+ return -1;
+ lrt = rt;
+ }
+
+ /* if this is a kernel policy, we are done - otherwise we need to
+ * convert these structs to range_trans_rule_ts */
+ if (p->policy_type == POLICY_KERN)
+ return 0;
+
+ /* create range_trans_rules_ts that correspond to the range_trans_ts
+ * that were just read in from an older policy */
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ rtr = malloc(sizeof(range_trans_rule_t));
+ if (!rtr) {
+ return -1;
+ }
+ range_trans_rule_init(rtr);
+
+ if (lrtr)
+ lrtr->next = rtr;
+ else
+ p->global->enabled->range_tr_rules = rtr;
+
+ if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
+ return -1;
+
+ if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
+ return -1;
+
+ if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
+ return -1;
+
+ if (mls_range_to_semantic(&rt->target_range, &rtr->trange))
+ return -1;
+
+ lrtr = rtr;
+ }
+
+ /* now destroy the range_trans_ts */
+ lrt = NULL;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ lrt = rt;
+ }
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ p->range_tr = NULL;
+
+ return 0;
+}
+
+int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+ struct policy_file *fp)
+{
+ unsigned int i;
+ avrule_t *cur, *tail;
+ uint32_t buf[1], len;
+ int rc;
+
+ *avrules = tail = NULL;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ return -1;
+ }
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ cur = avrule_read(p, fp);
+ if (!cur) {
+ return -1;
+ }
+
+ if (!tail) {
+ *avrules = cur;
+ } else {
+ tail->next = cur;
+ }
+ tail = cur;
+ }
+
+ return 0;
+}
+
+static int role_trans_rule_read(policydb_t *p, role_trans_rule_t ** r,
+ struct policy_file *fp)
+{
+ uint32_t buf[1], nel;
+ unsigned int i;
+ role_trans_rule_t *tr, *ltr;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ ltr = NULL;
+ for (i = 0; i < nel; i++) {
+ tr = malloc(sizeof(role_trans_rule_t));
+ if (!tr) {
+ return -1;
+ }
+ role_trans_rule_init(tr);
+
+ if (ltr) {
+ ltr->next = tr;
+ } else {
+ *r = tr;
+ }
+
+ if (role_set_read(&tr->roles, fp))
+ return -1;
+
+ if (type_set_read(&tr->types, fp))
+ return -1;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS) {
+ if (ebitmap_read(&tr->classes, fp))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(&tr->classes, SECCLASS_PROCESS - 1, 1))
+ return -1;
+ }
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ tr->new_role = le32_to_cpu(buf[0]);
+ ltr = tr;
+ }
+
+ return 0;
+}
+
+static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1], nel;
+ role_allow_rule_t *ra, *lra;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lra = NULL;
+ for (i = 0; i < nel; i++) {
+ ra = malloc(sizeof(role_allow_rule_t));
+ if (!ra) {
+ return -1;
+ }
+ role_allow_rule_init(ra);
+
+ if (lra) {
+ lra->next = ra;
+ } else {
+ *r = ra;
+ }
+
+ if (role_set_read(&ra->roles, fp))
+ return -1;
+
+ if (role_set_read(&ra->new_roles, fp))
+ return -1;
+
+ lra = ra;
+ }
+ return 0;
+}
+
+static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_file *fp)
+{
+ uint32_t buf[2], nel;
+ unsigned int i, len;
+ filename_trans_rule_t *ftr, *lftr;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lftr = NULL;
+ for (i = 0; i < nel; i++) {
+ ftr = malloc(sizeof(*ftr));
+ if (!ftr)
+ return -1;
+
+ filename_trans_rule_init(ftr);
+
+ if (lftr)
+ lftr->next = ftr;
+ else
+ *r = ftr;
+ lftr = ftr;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+
+ ftr->name = malloc(len + 1);
+ if (!ftr->name)
+ return -1;
+
+ rc = next_entry(ftr->name, fp, len);
+ if (rc)
+ return -1;
+ ftr->name[len] = 0;
+
+ if (type_set_read(&ftr->stypes, fp))
+ return -1;
+
+ if (type_set_read(&ftr->ttypes, fp))
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ ftr->tclass = le32_to_cpu(buf[0]);
+ ftr->otype = le32_to_cpu(buf[1]);
+ }
+
+ return 0;
+}
+
+static int range_trans_rule_read(range_trans_rule_t ** r,
+ struct policy_file *fp)
+{
+ uint32_t buf[1], nel;
+ unsigned int i;
+ range_trans_rule_t *rt, *lrt = NULL;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ for (i = 0; i < nel; i++) {
+ rt = malloc(sizeof(range_trans_rule_t));
+ if (!rt) {
+ return -1;
+ }
+ range_trans_rule_init(rt);
+
+ if (lrt)
+ lrt->next = rt;
+ else
+ *r = rt;
+
+ if (type_set_read(&rt->stypes, fp))
+ return -1;
+
+ if (type_set_read(&rt->ttypes, fp))
+ return -1;
+
+ if (ebitmap_read(&rt->tclasses, fp))
+ return -1;
+
+ if (mls_read_semantic_range_helper(&rt->trange, fp))
+ return -1;
+
+ lrt = rt;
+ }
+
+ return 0;
+}
+
+static int scope_index_read(scope_index_t * scope_index,
+ unsigned int num_scope_syms, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1];
+ int rc;
+
+ for (i = 0; i < num_scope_syms; i++) {
+ if (ebitmap_read(scope_index->scope + i, fp) == -1) {
+ return -1;
+ }
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ scope_index->class_perms_len = le32_to_cpu(buf[0]);
+ if (scope_index->class_perms_len == 0) {
+ scope_index->class_perms_map = NULL;
+ return 0;
+ }
+ if ((scope_index->class_perms_map =
+ calloc(scope_index->class_perms_len,
+ sizeof(*scope_index->class_perms_map))) == NULL) {
+ return -1;
+ }
+ for (i = 0; i < scope_index->class_perms_len; i++) {
+ if (ebitmap_read(scope_index->class_perms_map + i, fp) == -1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
+ unsigned int num_scope_syms, struct policy_file *fp)
+{
+ uint32_t buf[2], nprim, nel;
+ unsigned int i, j;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ decl->decl_id = le32_to_cpu(buf[0]);
+ decl->enabled = le32_to_cpu(buf[1]);
+ if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
+ avrule_read_list(p, &decl->avrules, fp) == -1 ||
+ role_trans_rule_read(p, &decl->role_tr_rules, fp) == -1 ||
+ role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
+ return -1;
+ }
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_rule_read(&decl->filename_trans_rules, fp))
+ return -1;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+ range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
+ return -1;
+ }
+ if (scope_index_read(&decl->required, num_scope_syms, fp) == -1 ||
+ scope_index_read(&decl->declared, num_scope_syms, fp) == -1) {
+ return -1;
+ }
+
+ for (i = 0; i < num_scope_syms; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ nprim = le32_to_cpu(buf[0]);
+ nel = le32_to_cpu(buf[1]);
+ for (j = 0; j < nel; j++) {
+ if (read_f[i] (p, decl->symtab[i].table, fp)) {
+ return -1;
+ }
+ }
+ decl->symtab[i].nprim = nprim;
+ }
+ return 0;
+}
+
+static int avrule_block_read(policydb_t * p,
+ avrule_block_t ** block,
+ unsigned int num_scope_syms,
+ struct policy_file *fp)
+{
+ avrule_block_t *last_block = NULL, *curblock;
+ uint32_t buf[1], num_blocks, nel;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ num_blocks = le32_to_cpu(buf[0]);
+ nel = num_blocks;
+ while (num_blocks > 0) {
+ avrule_decl_t *last_decl = NULL, *curdecl;
+ uint32_t num_decls;
+ if ((curblock = calloc(1, sizeof(*curblock))) == NULL) {
+ return -1;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ free(curblock);
+ return -1;
+ }
+ /* if this is the first block its non-optional, else its optional */
+ if (num_blocks != nel)
+ curblock->flags |= AVRULE_OPTIONAL;
+
+ num_decls = le32_to_cpu(buf[0]);
+ while (num_decls > 0) {
+ if ((curdecl = avrule_decl_create(0)) == NULL) {
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ if (avrule_decl_read(p, curdecl, num_scope_syms, fp) ==
+ -1) {
+ avrule_decl_destroy(curdecl);
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ if (curdecl->enabled) {
+ if (curblock->enabled != NULL) {
+ /* probably a corrupt file */
+ avrule_decl_destroy(curdecl);
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ curblock->enabled = curdecl;
+ }
+ /* one must be careful to reconstruct the
+ * decl chain in its correct order */
+ if (curblock->branch_list == NULL) {
+ curblock->branch_list = curdecl;
+ } else {
+ last_decl->next = curdecl;
+ }
+ last_decl = curdecl;
+ num_decls--;
+ }
+
+ if (*block == NULL) {
+ *block = curblock;
+ } else {
+ last_block->next = curblock;
+ }
+ last_block = curblock;
+
+ num_blocks--;
+ }
+
+ return 0;
+}
+
+static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
+{
+ scope_datum_t *scope = NULL;
+ uint32_t buf[2];
+ char *key = NULL;
+ size_t key_len;
+ unsigned int i;
+ hashtab_t h = p->scope[symnum].table;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto cleanup;
+ key_len = le32_to_cpu(buf[0]);
+ key = malloc(key_len + 1);
+ if (!key)
+ goto cleanup;
+ rc = next_entry(key, fp, key_len);
+ if (rc < 0)
+ goto cleanup;
+ key[key_len] = '\0';
+
+ /* ensure that there already exists a symbol with this key */
+ if (hashtab_search(p->symtab[symnum].table, key) == NULL) {
+ goto cleanup;
+ }
+
+ if ((scope = calloc(1, sizeof(*scope))) == NULL) {
+ goto cleanup;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto cleanup;
+ scope->scope = le32_to_cpu(buf[0]);
+ scope->decl_ids_len = le32_to_cpu(buf[1]);
+ assert(scope->decl_ids_len > 0);
+ if ((scope->decl_ids =
+ malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) {
+ goto cleanup;
+ }
+ rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len);
+ if (rc < 0)
+ goto cleanup;
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ scope->decl_ids[i] = le32_to_cpu(scope->decl_ids[i]);
+ }
+
+ if (strcmp(key, "object_r") == 0 && h == p->p_roles_scope.table) {
+ /* object_r was already added to this table in roles_init() */
+ scope_destroy(key, scope, NULL);
+ } else {
+ if (hashtab_insert(h, key, scope)) {
+ goto cleanup;
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ scope_destroy(key, scope, NULL);
+ return -1;
+}
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
+{
+
+ unsigned int i, j, r_policyvers;
+ uint32_t buf[5];
+ size_t len, nprim, nel;
+ char *policydb_str;
+ struct policydb_compat_info *info;
+ unsigned int policy_type, bufindex;
+ ebitmap_node_t *tnode;
+ int rc;
+
+ /* Read the magic number and string length. */
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return POLICYDB_ERROR;
+ for (i = 0; i < 2; i++)
+ buf[i] = le32_to_cpu(buf[i]);
+
+ if (buf[0] == POLICYDB_MAGIC) {
+ policy_type = POLICY_KERN;
+ } else if (buf[0] == POLICYDB_MOD_MAGIC) {
+ policy_type = POLICY_MOD;
+ } else {
+ ERR(fp->handle, "policydb magic number %#08x does not "
+ "match expected magic number %#08x or %#08x",
+ buf[0], POLICYDB_MAGIC, POLICYDB_MOD_MAGIC);
+ return POLICYDB_ERROR;
+ }
+
+ len = buf[1];
+ if (len > POLICYDB_STRING_MAX_LENGTH) {
+ ERR(fp->handle, "policydb string length too long ");
+ return POLICYDB_ERROR;
+ }
+
+ policydb_str = malloc(len + 1);
+ if (!policydb_str) {
+ ERR(fp->handle, "unable to allocate memory for policydb "
+ "string of length %zu", len);
+ return POLICYDB_ERROR;
+ }
+ rc = next_entry(policydb_str, fp, len);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated policydb string identifier");
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ policydb_str[len] = 0;
+
+ if (policy_type == POLICY_KERN) {
+ for (i = 0; i < POLICYDB_TARGET_SZ; i++) {
+ if ((strcmp(policydb_str, policydb_target_strings[i])
+ == 0)) {
+ policydb_set_target_platform(p, i);
+ break;
+ }
+ }
+
+ if (i == POLICYDB_TARGET_SZ) {
+ ERR(fp->handle, "cannot find a valid target for policy "
+ "string %s", policydb_str);
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ } else {
+ if (strcmp(policydb_str, POLICYDB_MOD_STRING)) {
+ ERR(fp->handle, "invalid string identifier %s",
+ policydb_str);
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ }
+
+ /* Done with policydb_str. */
+ free(policydb_str);
+ policydb_str = NULL;
+
+ /* Read the version, config, and table sizes (and policy type if it's a module). */
+ if (policy_type == POLICY_KERN)
+ nel = 4;
+ else
+ nel = 5;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * nel);
+ if (rc < 0)
+ return POLICYDB_ERROR;
+ for (i = 0; i < nel; i++)
+ buf[i] = le32_to_cpu(buf[i]);
+
+ bufindex = 0;
+
+ if (policy_type == POLICY_MOD) {
+ /* We know it's a module but not whether it's a base
+ module or regular binary policy module. buf[0]
+ tells us which. */
+ policy_type = buf[bufindex];
+ if (policy_type != POLICY_MOD && policy_type != POLICY_BASE) {
+ ERR(fp->handle, "unknown module type: %#08x",
+ policy_type);
+ return POLICYDB_ERROR;
+ }
+ bufindex++;
+ }
+
+ r_policyvers = buf[bufindex];
+ if (policy_type == POLICY_KERN) {
+ if (r_policyvers < POLICYDB_VERSION_MIN ||
+ r_policyvers > POLICYDB_VERSION_MAX) {
+ ERR(fp->handle, "policydb version %d does not match "
+ "my version range %d-%d", buf[bufindex],
+ POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+ return POLICYDB_ERROR;
+ }
+ } else if (policy_type == POLICY_BASE || policy_type == POLICY_MOD) {
+ if (r_policyvers < MOD_POLICYDB_VERSION_MIN ||
+ r_policyvers > MOD_POLICYDB_VERSION_MAX) {
+ ERR(fp->handle, "policydb module version %d does "
+ "not match my version range %d-%d",
+ buf[bufindex], MOD_POLICYDB_VERSION_MIN,
+ MOD_POLICYDB_VERSION_MAX);
+ return POLICYDB_ERROR;
+ }
+ } else {
+ assert(0);
+ }
+ bufindex++;
+
+ /* Set the policy type and version from the read values. */
+ p->policy_type = policy_type;
+ p->policyvers = r_policyvers;
+
+ if (buf[bufindex] & POLICYDB_CONFIG_MLS) {
+ p->mls = 1;
+ } else {
+ p->mls = 0;
+ }
+
+ p->handle_unknown = buf[bufindex] & POLICYDB_CONFIG_UNKNOWN_MASK;
+
+ bufindex++;
+
+ info = policydb_lookup_compat(r_policyvers, policy_type,
+ p->target_platform);
+ if (!info) {
+ ERR(fp->handle, "unable to find policy compat info "
+ "for version %d", r_policyvers);
+ goto bad;
+ }
+
+ if (buf[bufindex] != info->sym_num
+ || buf[bufindex + 1] != info->ocon_num) {
+ ERR(fp->handle,
+ "policydb table sizes (%d,%d) do not " "match mine (%d,%d)",
+ buf[bufindex], buf[bufindex + 1], info->sym_num,
+ info->ocon_num);
+ goto bad;
+ }
+
+ if (p->policy_type == POLICY_MOD) {
+ /* Get the module name and version */
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ len = le32_to_cpu(buf[0]);
+ if ((p->name = malloc(len + 1)) == NULL) {
+ goto bad;
+ }
+ if ((rc = next_entry(p->name, fp, len)) < 0) {
+ goto bad;
+ }
+ p->name[len] = '\0';
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ len = le32_to_cpu(buf[0]);
+ if ((p->version = malloc(len + 1)) == NULL) {
+ goto bad;
+ }
+ if ((rc = next_entry(p->version, fp, len)) < 0) {
+ goto bad;
+ }
+ p->version[len] = '\0';
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_MOD)) {
+ if (ebitmap_read(&p->policycaps, fp))
+ goto bad;
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&p->permissive_map, fp))
+ goto bad;
+ }
+
+ for (i = 0; i < info->sym_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+ nprim = le32_to_cpu(buf[0]);
+ nel = le32_to_cpu(buf[1]);
+ for (j = 0; j < nel; j++) {
+ if (read_f[i] (p, p->symtab[i].table, fp))
+ goto bad;
+ }
+
+ p->symtab[i].nprim = nprim;
+ }
+
+ if (policy_type == POLICY_KERN) {
+ if (avtab_read(&p->te_avtab, fp, r_policyvers))
+ goto bad;
+ if (r_policyvers >= POLICYDB_VERSION_BOOL)
+ if (cond_read_list(p, &p->cond_list, fp))
+ goto bad;
+ if (role_trans_read(p, fp))
+ goto bad;
+ if (role_allow_read(&p->role_allow, fp))
+ goto bad;
+ if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_read(&p->filename_trans, fp))
+ goto bad;
+ } else {
+ /* first read the AV rule blocks, then the scope tables */
+ avrule_block_destroy(p->global);
+ p->global = NULL;
+ if (avrule_block_read(p, &p->global, info->sym_num, fp) == -1) {
+ goto bad;
+ }
+ for (i = 0; i < info->sym_num; i++) {
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ nel = le32_to_cpu(buf[0]);
+ for (j = 0; j < nel; j++) {
+ if (scope_read(p, i, fp))
+ goto bad;
+ }
+ }
+
+ }
+
+ if (policydb_index_decls(p))
+ goto bad;
+
+ if (policydb_index_classes(p))
+ goto bad;
+
+ if (policydb_index_others(fp->handle, p, verbose))
+ goto bad;
+
+ if (ocontext_read(info, p, fp) == -1) {
+ goto bad;
+ }
+
+ if (genfs_read(p, fp) == -1) {
+ goto bad;
+ }
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS)) {
+ if (range_read(p, fp)) {
+ goto bad;
+ }
+ }
+
+ if (policy_type == POLICY_KERN) {
+ p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+ p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+ if (!p->type_attr_map || !p->attr_type_map)
+ goto bad;
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_init(&p->type_attr_map[i]);
+ ebitmap_init(&p->attr_type_map[i]);
+ }
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (r_policyvers >= POLICYDB_VERSION_AVTAB) {
+ if (ebitmap_read(&p->type_attr_map[i], fp))
+ goto bad;
+ ebitmap_for_each_bit(&p->type_attr_map[i],
+ tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j)
+ || i == j)
+ continue;
+ if (ebitmap_set_bit
+ (&p->attr_type_map[j], i, 1))
+ goto bad;
+ }
+ }
+ /* add the type itself as the degenerate case */
+ if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+ goto bad;
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+ bad:
+ return POLICYDB_ERROR;
+}
+
+int policydb_reindex_users(policydb_t * p)
+{
+ unsigned int i = SYM_USERS;
+
+ if (p->user_val_to_struct)
+ free(p->user_val_to_struct);
+ if (p->sym_val_to_name[i])
+ free(p->sym_val_to_name[i]);
+
+ p->user_val_to_struct = (user_datum_t **)
+ malloc(p->p_users.nprim * sizeof(user_datum_t *));
+ if (!p->user_val_to_struct)
+ return -1;
+
+ p->sym_val_to_name[i] = (char **)
+ malloc(p->symtab[i].nprim * sizeof(char *));
+ if (!p->sym_val_to_name[i])
+ return -1;
+
+ if (hashtab_map(p->symtab[i].table, index_f[i], p))
+ return -1;
+
+ /* Expand user roles for context validity checking */
+ if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+ return -1;
+
+ return 0;
+}
+
+void policy_file_init(policy_file_t *pf)
+{
+ memset(pf, 0, sizeof(policy_file_t));
+}
+
+int policydb_set_target_platform(policydb_t *p, int platform)
+{
+ if (platform == SEPOL_TARGET_SELINUX)
+ p->target_platform = SEPOL_TARGET_SELINUX;
+ else if (platform == SEPOL_TARGET_XEN)
+ p->target_platform = SEPOL_TARGET_XEN;
+ else
+ return -1;
+
+ return 0;
+}
+
diff --git a/src/policydb_convert.c b/src/policydb_convert.c
new file mode 100644
index 0000000..32832bb
--- /dev/null
+++ b/src/policydb_convert.c
@@ -0,0 +1,100 @@
+#include <stdlib.h>
+
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/policydb/policydb.h>
+
+/* Construct a policydb from the supplied (data, len) pair */
+
+int policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, policydb_t * policydb)
+{
+
+ policy_file_t pf;
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ pf.handle = handle;
+
+ if (policydb_read(policydb, &pf, 0)) {
+ ERR(handle, "policy image is invalid");
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Write a policydb to a memory region, and return the (data, len) pair. */
+
+int policydb_to_image(sepol_handle_t * handle,
+ policydb_t * policydb, void **newdata, size_t * newlen)
+{
+
+ void *tmp_data = NULL;
+ size_t tmp_len;
+ policy_file_t pf;
+ struct policydb tmp_policydb;
+
+ /* Compute the length for the new policy image. */
+ policy_file_init(&pf);
+ pf.type = PF_LEN;
+ pf.handle = handle;
+ if (policydb_write(policydb, &pf)) {
+ ERR(handle, "could not compute policy length");
+ errno = EINVAL;
+ goto err;
+ }
+
+ /* Allocate the new policy image. */
+ pf.type = PF_USE_MEMORY;
+ pf.data = malloc(pf.len);
+ if (!pf.data) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+
+ /* Need to save len and data prior to modification by policydb_write. */
+ tmp_len = pf.len;
+ tmp_data = pf.data;
+
+ /* Write out the new policy image. */
+ if (policydb_write(policydb, &pf)) {
+ ERR(handle, "could not write policy");
+ errno = EINVAL;
+ goto err;
+ }
+
+ /* Verify the new policy image. */
+ pf.type = PF_USE_MEMORY;
+ pf.data = tmp_data;
+ pf.len = tmp_len;
+ if (policydb_init(&tmp_policydb)) {
+ ERR(handle, "Out of memory");
+ errno = ENOMEM;
+ goto err;
+ }
+ if (policydb_read(&tmp_policydb, &pf, 0)) {
+ ERR(handle, "new policy image is invalid");
+ errno = EINVAL;
+ goto err;
+ }
+ policydb_destroy(&tmp_policydb);
+
+ /* Update (newdata, newlen) */
+ *newdata = tmp_data;
+ *newlen = tmp_len;
+
+ /* Recover */
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not create policy image");
+
+ /* Recover */
+ free(tmp_data);
+ return STATUS_ERR;
+}
diff --git a/src/policydb_internal.h b/src/policydb_internal.h
new file mode 100644
index 0000000..8a31506
--- /dev/null
+++ b/src/policydb_internal.h
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_POLICYDB_INTERNAL_H_
+#define _SEPOL_POLICYDB_INTERNAL_H_
+
+#include <sepol/policydb.h>
+#include "dso.h"
+
+hidden_proto(sepol_policydb_create)
+ hidden_proto(sepol_policydb_free)
+extern char *policydb_target_strings[];
+#endif
diff --git a/src/policydb_public.c b/src/policydb_public.c
new file mode 100644
index 0000000..f6ae793
--- /dev/null
+++ b/src/policydb_public.c
@@ -0,0 +1,193 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include <sepol/policydb/policydb.h>
+#include "policydb_internal.h"
+
+/* Policy file interfaces. */
+
+int sepol_policy_file_create(sepol_policy_file_t ** pf)
+{
+ *pf = calloc(1, sizeof(sepol_policy_file_t));
+ if (!(*pf))
+ return -1;
+ return 0;
+}
+
+void sepol_policy_file_set_mem(sepol_policy_file_t * spf,
+ char *data, size_t len)
+{
+ struct policy_file *pf = &spf->pf;
+ if (!len) {
+ pf->type = PF_LEN;
+ return;
+ }
+ pf->type = PF_USE_MEMORY;
+ pf->data = data;
+ pf->len = len;
+ pf->size = len;
+ return;
+}
+
+void sepol_policy_file_set_fp(sepol_policy_file_t * spf, FILE * fp)
+{
+ struct policy_file *pf = &spf->pf;
+ pf->type = PF_USE_STDIO;
+ pf->fp = fp;
+ return;
+}
+
+int sepol_policy_file_get_len(sepol_policy_file_t * spf, size_t * len)
+{
+ struct policy_file *pf = &spf->pf;
+ if (pf->type != PF_LEN)
+ return -1;
+ *len = pf->len;
+ return 0;
+}
+
+void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+ sepol_handle_t * handle)
+{
+ pf->pf.handle = handle;
+}
+
+void sepol_policy_file_free(sepol_policy_file_t * pf)
+{
+ free(pf);
+}
+
+/* Policydb interfaces. */
+
+int sepol_policydb_create(sepol_policydb_t ** sp)
+{
+ policydb_t *p;
+ *sp = malloc(sizeof(sepol_policydb_t));
+ if (!(*sp))
+ return -1;
+ p = &(*sp)->p;
+ if (policydb_init(p)) {
+ free(*sp);
+ return -1;
+ }
+ return 0;
+}
+
+hidden_def(sepol_policydb_create)
+
+void sepol_policydb_free(sepol_policydb_t * p)
+{
+ if (!p)
+ return;
+ policydb_destroy(&p->p);
+ free(p);
+}
+
+hidden_def(sepol_policydb_free)
+
+int sepol_policy_kern_vers_min(void)
+{
+ return POLICYDB_VERSION_MIN;
+}
+
+int sepol_policy_kern_vers_max(void)
+{
+ return POLICYDB_VERSION_MAX;
+}
+
+int sepol_policydb_set_typevers(sepol_policydb_t * sp, unsigned int type)
+{
+ struct policydb *p = &sp->p;
+ switch (type) {
+ case POLICY_KERN:
+ p->policyvers = POLICYDB_VERSION_MAX;
+ break;
+ case POLICY_BASE:
+ case POLICY_MOD:
+ p->policyvers = MOD_POLICYDB_VERSION_MAX;
+ break;
+ default:
+ return -1;
+ }
+ p->policy_type = type;
+ return 0;
+}
+
+int sepol_policydb_set_vers(sepol_policydb_t * sp, unsigned int vers)
+{
+ struct policydb *p = &sp->p;
+ switch (p->policy_type) {
+ case POLICY_KERN:
+ if (vers < POLICYDB_VERSION_MIN || vers > POLICYDB_VERSION_MAX)
+ return -1;
+ break;
+ case POLICY_BASE:
+ case POLICY_MOD:
+ if (vers < MOD_POLICYDB_VERSION_MIN
+ || vers > MOD_POLICYDB_VERSION_MAX)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ p->policyvers = vers;
+ return 0;
+}
+
+int sepol_policydb_set_handle_unknown(sepol_policydb_t * sp,
+ unsigned int handle_unknown)
+{
+ struct policydb *p = &sp->p;
+
+ switch (handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ case SEPOL_REJECT_UNKNOWN:
+ case SEPOL_ALLOW_UNKNOWN:
+ break;
+ default:
+ return -1;
+ }
+
+ p->handle_unknown = handle_unknown;
+ return 0;
+}
+
+int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+ return policydb_read(&p->p, &pf->pf, 0);
+}
+
+int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+ return policydb_write(&p->p, &pf->pf);
+}
+
+int sepol_policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, sepol_policydb_t * p)
+{
+ return policydb_from_image(handle, data, len, &p->p);
+}
+
+int sepol_policydb_to_image(sepol_handle_t * handle,
+ sepol_policydb_t * p, void **newdata,
+ size_t * newlen)
+{
+ return policydb_to_image(handle, &p->p, newdata, newlen);
+}
+
+int sepol_policydb_mls_enabled(const sepol_policydb_t * p)
+{
+
+ return p->p.mls;
+}
+
+/*
+ * Enable compatibility mode for SELinux network checks iff
+ * the packet class is not defined in the policy.
+ */
+#define PACKET_CLASS_NAME "packet"
+int sepol_policydb_compat_net(const sepol_policydb_t * p)
+{
+ return (hashtab_search(p->p.p_classes.table, PACKET_CLASS_NAME) ==
+ NULL);
+}
diff --git a/src/port_internal.h b/src/port_internal.h
new file mode 100644
index 0000000..ffb5f65
--- /dev/null
+++ b/src/port_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_PORT_INTERNAL_H_
+#define _SEPOL_PORT_INTERNAL_H_
+
+#include <sepol/port_record.h>
+#include <sepol/ports.h>
+#include "dso.h"
+
+hidden_proto(sepol_port_create)
+ hidden_proto(sepol_port_free)
+ hidden_proto(sepol_port_get_con)
+ hidden_proto(sepol_port_get_high)
+ hidden_proto(sepol_port_get_low)
+ hidden_proto(sepol_port_get_proto)
+ hidden_proto(sepol_port_get_proto_str)
+ hidden_proto(sepol_port_key_create)
+ hidden_proto(sepol_port_key_unpack)
+ hidden_proto(sepol_port_set_con)
+ hidden_proto(sepol_port_set_proto)
+ hidden_proto(sepol_port_set_range)
+#endif
diff --git a/src/port_record.c b/src/port_record.c
new file mode 100644
index 0000000..6a33d93
--- /dev/null
+++ b/src/port_record.c
@@ -0,0 +1,288 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_port {
+ /* Low - High range. Same for single ports. */
+ int low, high;
+
+ /* Protocol */
+ int proto;
+
+ /* Context */
+ sepol_context_t *con;
+};
+
+struct sepol_port_key {
+ /* Low - High range. Same for single ports. */
+ int low, high;
+
+ /* Protocol */
+ int proto;
+};
+
+/* Key */
+int sepol_port_key_create(sepol_handle_t * handle,
+ int low, int high, int proto,
+ sepol_port_key_t ** key_ptr)
+{
+
+ sepol_port_key_t *tmp_key =
+ (sepol_port_key_t *) malloc(sizeof(sepol_port_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, could not create " "port key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->low = low;
+ tmp_key->high = high;
+ tmp_key->proto = proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_key_create)
+
+void sepol_port_key_unpack(const sepol_port_key_t * key,
+ int *low, int *high, int *proto)
+{
+
+ *low = key->low;
+ *high = key->high;
+ *proto = key->proto;
+}
+
+hidden_def(sepol_port_key_unpack)
+
+int sepol_port_key_extract(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_key_t ** key_ptr)
+{
+
+ if (sepol_port_key_create
+ (handle, port->low, port->high, port->proto, key_ptr) < 0) {
+
+ ERR(handle, "could not extract key from port %s %d:%d",
+ sepol_port_get_proto_str(port->proto),
+ port->low, port->high);
+
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_port_key_free(sepol_port_key_t * key)
+{
+ free(key);
+}
+
+int sepol_port_compare(const sepol_port_t * port, const sepol_port_key_t * key)
+{
+
+ if ((port->low == key->low) &&
+ (port->high == key->high) && (port->proto == key->proto))
+ return 0;
+
+ if (port->low < key->low)
+ return -1;
+
+ else if (key->low < port->low)
+ return 1;
+
+ else if (port->high < key->high)
+ return -1;
+
+ else if (key->high < port->high)
+ return 1;
+
+ else if (port->proto < key->proto)
+ return -1;
+
+ else
+ return 1;
+}
+
+int sepol_port_compare2(const sepol_port_t * port, const sepol_port_t * port2)
+{
+
+ if ((port->low == port2->low) &&
+ (port->high == port2->high) && (port->proto == port2->proto))
+ return 0;
+
+ if (port->low < port2->low)
+ return -1;
+
+ else if (port2->low < port->low)
+ return 1;
+
+ else if (port->high < port2->high)
+ return -1;
+
+ else if (port2->high < port->high)
+ return 1;
+
+ else if (port->proto < port2->proto)
+ return -1;
+
+ else
+ return 1;
+}
+
+/* Port */
+int sepol_port_get_low(const sepol_port_t * port)
+{
+
+ return port->low;
+}
+
+hidden_def(sepol_port_get_low)
+
+int sepol_port_get_high(const sepol_port_t * port)
+{
+
+ return port->high;
+}
+
+hidden_def(sepol_port_get_high)
+
+void sepol_port_set_port(sepol_port_t * port, int port_num)
+{
+
+ port->low = port_num;
+ port->high = port_num;
+}
+
+void sepol_port_set_range(sepol_port_t * port, int low, int high)
+{
+
+ port->low = low;
+ port->high = high;
+}
+
+hidden_def(sepol_port_set_range)
+
+/* Protocol */
+int sepol_port_get_proto(const sepol_port_t * port)
+{
+
+ return port->proto;
+}
+
+hidden_def(sepol_port_get_proto)
+
+const char *sepol_port_get_proto_str(int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_UDP:
+ return "udp";
+ case SEPOL_PROTO_TCP:
+ return "tcp";
+ default:
+ return "???";
+ }
+}
+
+hidden_def(sepol_port_get_proto_str)
+
+void sepol_port_set_proto(sepol_port_t * port, int proto)
+{
+
+ port->proto = proto;
+}
+
+hidden_def(sepol_port_set_proto)
+
+/* Create */
+int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port)
+{
+
+ sepol_port_t *tmp_port = (sepol_port_t *) malloc(sizeof(sepol_port_t));
+
+ if (!tmp_port) {
+ ERR(handle, "out of memory, could not create " "port record");
+ return STATUS_ERR;
+ }
+
+ tmp_port->low = 0;
+ tmp_port->high = 0;
+ tmp_port->proto = SEPOL_PROTO_UDP;
+ tmp_port->con = NULL;
+ *port = tmp_port;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_create)
+
+/* Deep copy clone */
+int sepol_port_clone(sepol_handle_t * handle,
+ const sepol_port_t * port, sepol_port_t ** port_ptr)
+{
+
+ sepol_port_t *new_port = NULL;
+ if (sepol_port_create(handle, &new_port) < 0)
+ goto err;
+
+ new_port->low = port->low;
+ new_port->high = port->high;
+ new_port->proto = port->proto;
+
+ if (port->con &&
+ (sepol_context_clone(handle, port->con, &new_port->con) < 0))
+ goto err;
+
+ *port_ptr = new_port;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone port record");
+ sepol_port_free(new_port);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_port_free(sepol_port_t * port)
+{
+
+ if (!port)
+ return;
+
+ sepol_context_free(port->con);
+ free(port);
+}
+
+hidden_def(sepol_port_free)
+
+/* Context */
+sepol_context_t *sepol_port_get_con(const sepol_port_t * port)
+{
+
+ return port->con;
+}
+
+hidden_def(sepol_port_get_con)
+
+int sepol_port_set_con(sepol_handle_t * handle,
+ sepol_port_t * port, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set port context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(port->con);
+ port->con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_set_con)
diff --git a/src/ports.c b/src/ports.c
new file mode 100644
index 0000000..cbf2a0b
--- /dev/null
+++ b/src/ports.c
@@ -0,0 +1,312 @@
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "port_internal.h"
+
+static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_TCP:
+ return IPPROTO_TCP;
+ case SEPOL_PROTO_UDP:
+ return IPPROTO_UDP;
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ return STATUS_ERR;
+ }
+}
+
+static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
+{
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ return SEPOL_PROTO_TCP;
+ case IPPROTO_UDP:
+ return SEPOL_PROTO_UDP;
+ default:
+ ERR(handle, "invalid protocol %u " "found in policy", proto);
+ return STATUS_ERR;
+ }
+}
+
+/* Create a low level port structure from
+ * a high level representation */
+static int port_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** port, const sepol_port_t * data)
+{
+
+ ocontext_t *tmp_port = NULL;
+ context_struct_t *tmp_con = NULL;
+ int tmp_proto;
+
+ int low = sepol_port_get_low(data);
+ int high = sepol_port_get_high(data);
+ int proto = sepol_port_get_proto(data);
+
+ tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_port)
+ goto omem;
+
+ /* Process protocol */
+ tmp_proto = sepol2ipproto(handle, proto);
+ if (tmp_proto < 0)
+ goto err;
+ tmp_port->u.port.protocol = tmp_proto;
+
+ /* Port range */
+ tmp_port->u.port.low_port = low;
+ tmp_port->u.port.high_port = high;
+ if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
+ ERR(handle, "low port %d exceeds high port %d",
+ tmp_port->u.port.low_port, tmp_port->u.port.high_port);
+ goto err;
+ }
+
+ /* Context */
+ if (context_from_record(handle, policydb, &tmp_con,
+ sepol_port_get_con(data)) < 0)
+ goto err;
+ context_cpy(&tmp_port->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *port = tmp_port;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_port != NULL) {
+ context_destroy(&tmp_port->context[0]);
+ free(tmp_port);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ ERR(handle, "could not create port structure for range %u:%u (%s)",
+ low, high, sepol_port_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+static int port_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * port, sepol_port_t ** record)
+{
+
+ int proto = port->u.port.protocol;
+ int low = port->u.port.low_port;
+ int high = port->u.port.high_port;
+ context_struct_t *con = &port->context[0];
+ int rec_proto = -1;
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_port_t *tmp_record = NULL;
+
+ if (sepol_port_create(handle, &tmp_record) < 0)
+ goto err;
+
+ rec_proto = ipproto2sepol(handle, proto);
+ if (rec_proto < 0)
+ goto err;
+
+ sepol_port_set_proto(tmp_record, rec_proto);
+ sepol_port_set_range(tmp_record, low, high);
+
+ if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+ goto err;
+
+ if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
+ goto err;
+
+ sepol_context_free(tmp_con);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert port range %u - %u (%s) "
+ "to record", low, high, sepol_port_get_proto_str(rec_proto));
+ sepol_context_free(tmp_con);
+ sepol_port_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+/* Check if a port exists */
+int sepol_port_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_port_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int low, high, proto;
+ const char *proto_str;
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int proto2 = c->u.port.protocol;
+ int low2 = c->u.port.low_port;
+ int high2 = c->u.port.high_port;
+
+ if (proto == proto2 && low2 == low && high2 == high) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = 0;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not check if port range %u - %u (%s) exists",
+ low, high, proto_str);
+ return STATUS_ERR;
+}
+
+/* Query a port */
+int sepol_port_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_port_key_t * key, sepol_port_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int low, high, proto;
+ const char *proto_str;
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int proto2 = c->u.port.protocol;
+ int low2 = c->u.port.low_port;
+ int high2 = c->u.port.high_port;
+
+ if (proto == proto2 && low2 == low && high2 == high) {
+ if (port_to_record(handle, policydb, c, response) < 0)
+ goto err;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query port range %u - %u (%s)",
+ low, high, proto_str);
+ return STATUS_ERR;
+
+}
+
+/* Load a port into policy */
+int sepol_port_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_port_key_t * key, const sepol_port_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *port = NULL;
+
+ int low, high, proto;
+ const char *proto_str;
+
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ if (port_from_record(handle, policydb, &port, data) < 0)
+ goto err;
+
+ /* Attach to context list */
+ port->next = policydb->ocontexts[OCON_PORT];
+ policydb->ocontexts[OCON_PORT] = port;
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not load port range %u - %u (%s)",
+ low, high, proto_str);
+ if (port != NULL) {
+ context_destroy(&port->context[0]);
+ free(port);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_port_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_port_t * port,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_port_t *port = NULL;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int status;
+
+ if (port_to_record(handle, policydb, c, &port) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(port, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_port_free(port);
+ port = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over ports");
+ sepol_port_free(port);
+ return STATUS_ERR;
+}
diff --git a/src/private.h b/src/private.h
new file mode 100644
index 0000000..b2b247e
--- /dev/null
+++ b/src/private.h
@@ -0,0 +1,49 @@
+/* Private definitions for libsepol. */
+
+/* Endian conversion for reading and writing binary policies */
+
+#include <sepol/policydb/policydb.h>
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <dso.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+#define le64_to_cpu(x) (x)
+#else
+#define cpu_to_le16(x) bswap_16(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#define le64_to_cpu(x) bswap_64(x)
+#endif
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+/* Policy compatibility information. */
+struct policydb_compat_info {
+ unsigned int type;
+ unsigned int version;
+ unsigned int sym_num;
+ unsigned int ocon_num;
+ unsigned int target_platform;
+};
+
+extern struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+ unsigned int type,
+ unsigned int target_platform);
+
+/* Reading from a policy "file". */
+extern int next_entry(void *buf, struct policy_file *fp, size_t bytes) hidden;
+extern size_t put_entry(const void *ptr, size_t size, size_t n,
+ struct policy_file *fp) hidden;
diff --git a/src/roles.c b/src/roles.c
new file mode 100644
index 0000000..419a3b2
--- /dev/null
+++ b/src/roles.c
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "handle.h"
+
+/* Check if a role exists */
+int sepol_role_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ sepol_policydb_t * p, const char *role, int *response)
+{
+
+ policydb_t *policydb = &p->p;
+ *response = (hashtab_search(policydb->p_roles.table,
+ (const hashtab_key_t)role) != NULL);
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+/* Fill an array with all valid roles */
+int sepol_role_list(sepol_handle_t * handle,
+ sepol_policydb_t * p, char ***roles, unsigned int *nroles)
+{
+
+ policydb_t *policydb = &p->p;
+ unsigned int tmp_nroles = policydb->p_roles.nprim;
+ char **tmp_roles = (char **)malloc(tmp_nroles * sizeof(char *));
+ char **ptr;
+ unsigned int i;
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < tmp_nroles; i++) {
+ tmp_roles[i] = strdup(policydb->p_role_val_to_name[i]);
+ if (!tmp_roles[i])
+ goto omem;
+ }
+
+ *nroles = tmp_nroles;
+ *roles = tmp_roles;
+
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not list roles");
+
+ ptr = tmp_roles;
+ while (ptr && *ptr)
+ free(*ptr++);
+ free(tmp_roles);
+ return STATUS_ERR;
+}
diff --git a/src/services.c b/src/services.c
new file mode 100644
index 0000000..9c2920c
--- /dev/null
+++ b/src/services.c
@@ -0,0 +1,1469 @@
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the security services.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/sidtab.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+
+#include "debug.h"
+#include "private.h"
+#include "context.h"
+#include "av_permissions.h"
+#include "dso.h"
+#include "mls.h"
+
+#define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+#define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+
+static int selinux_enforcing = 1;
+
+static sidtab_t mysidtab, *sidtab = &mysidtab;
+static policydb_t mypolicydb, *policydb = &mypolicydb;
+
+int hidden sepol_set_sidtab(sidtab_t * s)
+{
+ sidtab = s;
+ return 0;
+}
+
+int hidden sepol_set_policydb(policydb_t * p)
+{
+ policydb = p;
+ return 0;
+}
+
+int sepol_set_policydb_from_file(FILE * fp)
+{
+ struct policy_file pf;
+
+ policy_file_init(&pf);
+ pf.fp = fp;
+ pf.type = PF_USE_STDIO;
+ if (mypolicydb.policy_type)
+ policydb_destroy(&mypolicydb);
+ if (policydb_init(&mypolicydb)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ if (policydb_read(&mypolicydb, &pf, 0)) {
+ ERR(NULL, "can't read binary policy: %s", strerror(errno));
+ return -1;
+ }
+ policydb = &mypolicydb;
+ return sepol_sidtab_init(sidtab);
+}
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static uint32_t latest_granting = 0;
+
+/*
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast... It is used by the validatetrans rules
+ * only. For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition. All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
+ */
+static int constraint_expr_eval(context_struct_t * scontext,
+ context_struct_t * tcontext,
+ context_struct_t * xcontext,
+ constraint_expr_t * cexpr)
+{
+ uint32_t val1, val2;
+ context_struct_t *c;
+ role_datum_t *r1, *r2;
+ mls_level_t *l1, *l2;
+ constraint_expr_t *e;
+ int s[CEXPR_MAXDEPTH];
+ int sp = -1;
+
+ for (e = cexpr; e; e = e->next) {
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ BUG_ON(sp < 0);
+ s[sp] = !s[sp];
+ break;
+ case CEXPR_AND:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] &= s[sp + 1];
+ break;
+ case CEXPR_OR:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] |= s[sp + 1];
+ break;
+ case CEXPR_ATTR:
+ if (sp == (CEXPR_MAXDEPTH - 1))
+ return 0;
+ switch (e->attr) {
+ case CEXPR_USER:
+ val1 = scontext->user;
+ val2 = tcontext->user;
+ break;
+ case CEXPR_TYPE:
+ val1 = scontext->type;
+ val2 = tcontext->type;
+ break;
+ case CEXPR_ROLE:
+ val1 = scontext->role;
+ val2 = tcontext->role;
+ r1 = policydb->role_val_to_struct[val1 - 1];
+ r2 = policydb->role_val_to_struct[val2 - 1];
+ switch (e->op) {
+ case CEXPR_DOM:
+ s[++sp] =
+ ebitmap_get_bit(&r1->dominates,
+ val2 - 1);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] =
+ ebitmap_get_bit(&r2->dominates,
+ val1 - 1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] =
+ (!ebitmap_get_bit
+ (&r1->dominates, val2 - 1)
+ && !ebitmap_get_bit(&r2->dominates,
+ val1 - 1));
+ continue;
+ default:
+ break;
+ }
+ break;
+ case CEXPR_L1L2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_L1H2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_H1L2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_H1H2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L1H1:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(scontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L2H2:
+ l1 = &(tcontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ mls_ops:
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_NEQ:
+ s[++sp] = !mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_DOM:
+ s[++sp] = mls_level_dom(l1, l2);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = mls_level_dom(l2, l1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = mls_level_incomp(l2, l1);
+ continue;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = (val1 == val2);
+ break;
+ case CEXPR_NEQ:
+ s[++sp] = (val1 != val2);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ case CEXPR_NAMES:
+ if (sp == (CEXPR_MAXDEPTH - 1))
+ return 0;
+ c = scontext;
+ if (e->attr & CEXPR_TARGET)
+ c = tcontext;
+ else if (e->attr & CEXPR_XTARGET) {
+ c = xcontext;
+ if (!c) {
+ BUG();
+ return 0;
+ }
+ }
+ if (e->attr & CEXPR_USER)
+ val1 = c->user;
+ else if (e->attr & CEXPR_ROLE)
+ val1 = c->role;
+ else if (e->attr & CEXPR_TYPE)
+ val1 = c->type;
+ else {
+ BUG();
+ return 0;
+ }
+
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+ break;
+ case CEXPR_NEQ:
+ s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ }
+
+ BUG_ON(sp != 0);
+ return s[0];
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason)
+{
+ constraint_node_t *constraint;
+ struct role_allow *ra;
+ avtab_key_t avkey;
+ class_datum_t *tclass_datum;
+ avtab_ptr_t node;
+ ebitmap_t *sattr, *tattr;
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ /*
+ * Initialize the access vectors to the default values.
+ */
+ avd->allowed = 0;
+ avd->decided = 0xffffffff;
+ avd->auditallow = 0;
+ avd->auditdeny = 0xffffffff;
+ avd->seqno = latest_granting;
+ *reason = 0;
+
+ /*
+ * If a specific type enforcement rule was defined for
+ * this permission check, then use it.
+ */
+ avkey.target_class = tclass;
+ avkey.specified = AVTAB_AV;
+ sattr = &policydb->type_attr_map[scontext->type - 1];
+ tattr = &policydb->type_attr_map[tcontext->type - 1];
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ avkey.source_type = i + 1;
+ avkey.target_type = j + 1;
+ for (node =
+ avtab_search_node(&policydb->te_avtab, &avkey);
+ node != NULL;
+ node =
+ avtab_search_node_next(node, avkey.specified)) {
+ if (node->key.specified == AVTAB_ALLOWED)
+ avd->allowed |= node->datum.data;
+ else if (node->key.specified ==
+ AVTAB_AUDITALLOW)
+ avd->auditallow |= node->datum.data;
+ else if (node->key.specified == AVTAB_AUDITDENY)
+ avd->auditdeny &= node->datum.data;
+ }
+
+ /* Check conditional av table for additional permissions */
+ cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
+
+ }
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_TE;
+ requested &= avd->allowed;
+ }
+
+ /*
+ * Remove any permissions prohibited by a constraint (this includes
+ * the MLS policy).
+ */
+ constraint = tclass_datum->constraints;
+ while (constraint) {
+ if ((constraint->permissions & (avd->allowed)) &&
+ !constraint_expr_eval(scontext, tcontext, NULL,
+ constraint->expr)) {
+ avd->allowed =
+ (avd->allowed) & ~(constraint->permissions);
+ }
+ constraint = constraint->next;
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_CONS;
+ requested &= avd->allowed;
+ }
+
+ /*
+ * If checking process transition permission and the
+ * role is changing, then check the (current_role, new_role)
+ * pair.
+ */
+ if (tclass == SECCLASS_PROCESS &&
+ (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
+ scontext->role != tcontext->role) {
+ for (ra = policydb->role_allow; ra; ra = ra->next) {
+ if (scontext->role == ra->role &&
+ tcontext->role == ra->new_role)
+ break;
+ }
+ if (!ra)
+ avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
+ PROCESS__DYNTRANSITION);
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_RBAC;
+ requested &= avd->allowed;
+ }
+
+ return 0;
+}
+
+int hidden sepol_validate_transition(sepol_security_id_t oldsid,
+ sepol_security_id_t newsid,
+ sepol_security_id_t tasksid,
+ sepol_security_class_t tclass)
+{
+ context_struct_t *ocontext;
+ context_struct_t *ncontext;
+ context_struct_t *tcontext;
+ class_datum_t *tclass_datum;
+ constraint_node_t *constraint;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ ocontext = sepol_sidtab_search(sidtab, oldsid);
+ if (!ocontext) {
+ ERR(NULL, "unrecognized SID %d", oldsid);
+ return -EINVAL;
+ }
+
+ ncontext = sepol_sidtab_search(sidtab, newsid);
+ if (!ncontext) {
+ ERR(NULL, "unrecognized SID %d", newsid);
+ return -EINVAL;
+ }
+
+ tcontext = sepol_sidtab_search(sidtab, tasksid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tasksid);
+ return -EINVAL;
+ }
+
+ constraint = tclass_datum->validatetrans;
+ while (constraint) {
+ if (!constraint_expr_eval(ocontext, ncontext, tcontext,
+ constraint->expr)) {
+ return -EPERM;
+ }
+ constraint = constraint->next;
+ }
+
+ return 0;
+}
+
+int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason)
+{
+ context_struct_t *scontext = 0, *tcontext = 0;
+ int rc = 0;
+
+ scontext = sepol_sidtab_search(sidtab, ssid);
+ if (!scontext) {
+ ERR(NULL, "unrecognized SID %d", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sepol_sidtab_search(sidtab, tsid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
+ requested, avd, reason);
+ out:
+ return rc;
+}
+
+int hidden sepol_compute_av(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd)
+{
+ unsigned int reason = 0;
+ return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
+ &reason);
+}
+
+/*
+ * Write the security context string representation of
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int hidden sepol_sid_to_context(sepol_security_id_t sid,
+ sepol_security_context_t * scontext,
+ size_t * scontext_len)
+{
+ context_struct_t *context;
+ int rc = 0;
+
+ context = sepol_sidtab_search(sidtab, sid);
+ if (!context) {
+ ERR(NULL, "unrecognized SID %d", sid);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
+ out:
+ return rc;
+
+}
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
+ size_t scontext_len, sepol_security_id_t * sid)
+{
+
+ context_struct_t *context = NULL;
+
+ /* First, create the context */
+ if (context_from_string(NULL, policydb, &context,
+ scontext, scontext_len) < 0)
+ goto err;
+
+ /* Obtain the new sid */
+ if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
+ goto err;
+
+ context_destroy(context);
+ free(context);
+ return STATUS_SUCCESS;
+
+ err:
+ if (context) {
+ context_destroy(context);
+ free(context);
+ }
+ ERR(NULL, "could not convert %s to sid", scontext);
+ return STATUS_ERR;
+}
+
+static inline int compute_sid_handle_invalid_context(context_struct_t *
+ scontext,
+ context_struct_t *
+ tcontext,
+ sepol_security_class_t
+ tclass,
+ context_struct_t *
+ newcontext)
+{
+ if (selinux_enforcing) {
+ return -EACCES;
+ } else {
+ sepol_security_context_t s, t, n;
+ size_t slen, tlen, nlen;
+
+ context_to_string(NULL, policydb, scontext, &s, &slen);
+ context_to_string(NULL, policydb, tcontext, &t, &tlen);
+ context_to_string(NULL, policydb, newcontext, &n, &nlen);
+ ERR(NULL, "invalid context %s for "
+ "scontext=%s tcontext=%s tclass=%s",
+ n, s, t, policydb->p_class_val_to_name[tclass - 1]);
+ free(s);
+ free(t);
+ free(n);
+ return 0;
+ }
+}
+
+static int sepol_compute_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ uint32_t specified, sepol_security_id_t * out_sid)
+{
+ context_struct_t *scontext = 0, *tcontext = 0, newcontext;
+ struct role_trans *roletr = 0;
+ avtab_key_t avkey;
+ avtab_datum_t *avdatum;
+ avtab_ptr_t node;
+ int rc = 0;
+
+ scontext = sepol_sidtab_search(sidtab, ssid);
+ if (!scontext) {
+ ERR(NULL, "unrecognized SID %d", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sepol_sidtab_search(sidtab, tsid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ context_init(&newcontext);
+
+ /* Set the user identity. */
+ switch (specified) {
+ case AVTAB_TRANSITION:
+ case AVTAB_CHANGE:
+ /* Use the process user identity. */
+ newcontext.user = scontext->user;
+ break;
+ case AVTAB_MEMBER:
+ /* Use the related object owner. */
+ newcontext.user = tcontext->user;
+ break;
+ }
+
+ /* Set the role and type to default values. */
+ switch (tclass) {
+ case SECCLASS_PROCESS:
+ /* Use the current role and type of process. */
+ newcontext.role = scontext->role;
+ newcontext.type = scontext->type;
+ break;
+ default:
+ /* Use the well-defined object role. */
+ newcontext.role = OBJECT_R_VAL;
+ /* Use the type of the related object. */
+ newcontext.type = tcontext->type;
+ }
+
+ /* Look for a type transition/member/change rule. */
+ avkey.source_type = scontext->type;
+ avkey.target_type = tcontext->type;
+ avkey.target_class = tclass;
+ avkey.specified = specified;
+ avdatum = avtab_search(&policydb->te_avtab, &avkey);
+
+ /* If no permanent rule, also check for enabled conditional rules */
+ if (!avdatum) {
+ node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
+ for (; node != NULL;
+ node = avtab_search_node_next(node, specified)) {
+ if (node->key.specified & AVTAB_ENABLED) {
+ avdatum = &node->datum;
+ break;
+ }
+ }
+ }
+
+ if (avdatum) {
+ /* Use the type from the type transition/member/change rule. */
+ newcontext.type = avdatum->data;
+ }
+
+ /* Check for class-specific changes. */
+ switch (tclass) {
+ case SECCLASS_PROCESS:
+ if (specified & AVTAB_TRANSITION) {
+ /* Look for a role transition rule. */
+ for (roletr = policydb->role_tr; roletr;
+ roletr = roletr->next) {
+ if (roletr->role == scontext->role &&
+ roletr->type == tcontext->type) {
+ /* Use the role transition rule. */
+ newcontext.role = roletr->new_role;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Set the MLS attributes.
+ This is done last because it may allocate memory. */
+ rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
+ &newcontext);
+ if (rc)
+ goto out;
+
+ /* Check the validity of the context. */
+ if (!policydb_context_isvalid(policydb, &newcontext)) {
+ rc = compute_sid_handle_invalid_context(scontext,
+ tcontext,
+ tclass, &newcontext);
+ if (rc)
+ goto out;
+ }
+ /* Obtain the sid for the context. */
+ rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
+ out:
+ context_destroy(&newcontext);
+ return rc;
+}
+
+/*
+ * Compute a SID to use for labeling a new object in the
+ * class `tclass' based on a SID pair.
+ */
+int hidden sepol_transition_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/*
+ * Compute a SID to use when selecting a member of a
+ * polyinstantiated object of class `tclass' based on
+ * a SID pair.
+ */
+int hidden sepol_member_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/*
+ * Compute a SID to use for relabeling an object in the
+ * class `tclass' based on a SID pair.
+ */
+int hidden sepol_change_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+ hashtab_t h;
+ perm_datum_t *perdatum, *perdatum2;
+
+ h = (hashtab_t) p;
+ perdatum = (perm_datum_t *) datum;
+
+ perdatum2 = (perm_datum_t *) hashtab_search(h, key);
+ if (!perdatum2) {
+ ERR(NULL, "permission %s disappeared", key);
+ return -1;
+ }
+ if (perdatum->s.value != perdatum2->s.value) {
+ ERR(NULL, "the value of permissions %s changed", key);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ */
+static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+ policydb_t *newp;
+ class_datum_t *cladatum, *cladatum2;
+
+ newp = (policydb_t *) p;
+ cladatum = (class_datum_t *) datum;
+
+ cladatum2 =
+ (class_datum_t *) hashtab_search(newp->p_classes.table, key);
+ if (!cladatum2) {
+ ERR(NULL, "class %s disappeared", key);
+ return -1;
+ }
+ if (cladatum->s.value != cladatum2->s.value) {
+ ERR(NULL, "the value of class %s changed", key);
+ return -1;
+ }
+ if ((cladatum->comdatum && !cladatum2->comdatum) ||
+ (!cladatum->comdatum && cladatum2->comdatum)) {
+ ERR(NULL, "the inherits clause for the access "
+ "vector definition for class %s changed", key);
+ return -1;
+ }
+ if (cladatum->comdatum) {
+ if (hashtab_map
+ (cladatum->comdatum->permissions.table, validate_perm,
+ cladatum2->comdatum->permissions.table)) {
+ ERR(NULL,
+ " in the access vector definition "
+ "for class %s\n", key);
+ return -1;
+ }
+ }
+ if (hashtab_map(cladatum->permissions.table, validate_perm,
+ cladatum2->permissions.table)) {
+ ERR(NULL, " in access vector definition for class %s", key);
+ return -1;
+ }
+ return 0;
+}
+
+/* Clone the SID into the new SID table. */
+static int clone_sid(sepol_security_id_t sid,
+ context_struct_t * context, void *arg)
+{
+ sidtab_t *s = arg;
+
+ return sepol_sidtab_insert(s, sid, context);
+}
+
+static inline int convert_context_handle_invalid_context(context_struct_t *
+ context)
+{
+ if (selinux_enforcing) {
+ return -EINVAL;
+ } else {
+ sepol_security_context_t s;
+ size_t len;
+
+ context_to_string(NULL, policydb, context, &s, &len);
+ ERR(NULL, "context %s is invalid", s);
+ free(s);
+ return 0;
+ }
+}
+
+typedef struct {
+ policydb_t *oldp;
+ policydb_t *newp;
+} convert_context_args_t;
+
+/*
+ * Convert the values in the security context
+ * structure `c' from the values specified
+ * in the policy `p->oldp' to the values specified
+ * in the policy `p->newp'. Verify that the
+ * context is valid under the new policy.
+ */
+static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
+ context_struct_t * c, void *p)
+{
+ convert_context_args_t *args;
+ context_struct_t oldc;
+ role_datum_t *role;
+ type_datum_t *typdatum;
+ user_datum_t *usrdatum;
+ sepol_security_context_t s;
+ size_t len;
+ int rc = -EINVAL;
+
+ args = (convert_context_args_t *) p;
+
+ if (context_cpy(&oldc, c))
+ return -ENOMEM;
+
+ /* Convert the user. */
+ usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
+ args->oldp->
+ p_user_val_to_name[c->user -
+ 1]);
+
+ if (!usrdatum) {
+ goto bad;
+ }
+ c->user = usrdatum->s.value;
+
+ /* Convert the role. */
+ role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
+ args->oldp->
+ p_role_val_to_name[c->role - 1]);
+ if (!role) {
+ goto bad;
+ }
+ c->role = role->s.value;
+
+ /* Convert the type. */
+ typdatum = (type_datum_t *)
+ hashtab_search(args->newp->p_types.table,
+ args->oldp->p_type_val_to_name[c->type - 1]);
+ if (!typdatum) {
+ goto bad;
+ }
+ c->type = typdatum->s.value;
+
+ rc = mls_convert_context(args->oldp, args->newp, c);
+ if (rc)
+ goto bad;
+
+ /* Check the validity of the new context. */
+ if (!policydb_context_isvalid(args->newp, c)) {
+ rc = convert_context_handle_invalid_context(&oldc);
+ if (rc)
+ goto bad;
+ }
+
+ context_destroy(&oldc);
+ return 0;
+
+ bad:
+ context_to_string(NULL, policydb, &oldc, &s, &len);
+ context_destroy(&oldc);
+ ERR(NULL, "invalidating context %s", s);
+ free(s);
+ return rc;
+}
+
+/* Reading from a policy "file". */
+int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
+{
+ size_t nread;
+
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ nread = fread(buf, bytes, 1, fp->fp);
+
+ if (nread != 1)
+ return -1;
+ break;
+ case PF_USE_MEMORY:
+ if (bytes > fp->len)
+ return -1;
+ memcpy(buf, fp->data, bytes);
+ fp->data += bytes;
+ fp->len -= bytes;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+size_t hidden put_entry(const void *ptr, size_t size, size_t n,
+ struct policy_file *fp)
+{
+ size_t bytes = size * n;
+
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ return fwrite(ptr, size, n, fp->fp);
+ case PF_USE_MEMORY:
+ if (bytes > fp->len) {
+ errno = ENOSPC;
+ return 0;
+ }
+
+ memcpy(fp->data, ptr, bytes);
+ fp->data += bytes;
+ fp->len -= bytes;
+ return n;
+ case PF_LEN:
+ fp->len += bytes;
+ return n;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * Read a new set of configuration data from
+ * a policy database binary representation file.
+ *
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ *
+ * Convert the context structures in the SID table to the
+ * new representation and verify that all entries
+ * in the SID table are valid under the new policy.
+ *
+ * Change the active policy database to use the new
+ * configuration data.
+ *
+ * Reset the access vector cache.
+ */
+int hidden sepol_load_policy(void *data, size_t len)
+{
+ policydb_t oldpolicydb, newpolicydb;
+ sidtab_t oldsidtab, newsidtab;
+ convert_context_args_t args;
+ int rc = 0;
+ struct policy_file file, *fp;
+
+ policy_file_init(&file);
+ file.type = PF_USE_MEMORY;
+ file.data = data;
+ file.len = len;
+ fp = &file;
+
+ if (policydb_init(&newpolicydb))
+ return -ENOMEM;
+
+ if (policydb_read(&newpolicydb, fp, 1)) {
+ return -EINVAL;
+ }
+
+ sepol_sidtab_init(&newsidtab);
+
+ /* Verify that the existing classes did not change. */
+ if (hashtab_map
+ (policydb->p_classes.table, validate_class, &newpolicydb)) {
+ ERR(NULL, "the definition of an existing class changed");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Clone the SID table. */
+ sepol_sidtab_shutdown(sidtab);
+ if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /* Convert the internal representations of contexts
+ in the new SID table and remove invalid SIDs. */
+ args.oldp = policydb;
+ args.newp = &newpolicydb;
+ sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+
+ /* Save the old policydb and SID table to free later. */
+ memcpy(&oldpolicydb, policydb, sizeof *policydb);
+ sepol_sidtab_set(&oldsidtab, sidtab);
+
+ /* Install the new policydb and SID table. */
+ memcpy(policydb, &newpolicydb, sizeof *policydb);
+ sepol_sidtab_set(sidtab, &newsidtab);
+
+ /* Free the old policydb and SID table. */
+ policydb_destroy(&oldpolicydb);
+ sepol_sidtab_destroy(&oldsidtab);
+
+ return 0;
+
+ err:
+ sepol_sidtab_destroy(&newsidtab);
+ policydb_destroy(&newpolicydb);
+ return rc;
+
+}
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'. The `fs_sid' SID is returned for
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+int hidden sepol_fs_sid(char *name,
+ sepol_security_id_t * fs_sid,
+ sepol_security_id_t * file_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_FS];
+ while (c) {
+ if (strcmp(c->u.name, name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0] || !c->sid[1]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[1],
+ &c->sid[1]);
+ if (rc)
+ goto out;
+ }
+ *fs_sid = c->sid[0];
+ *file_sid = c->sid[1];
+ } else {
+ *fs_sid = SECINITSID_FS;
+ *file_sid = SECINITSID_FILE;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
+ uint16_t type __attribute__ ((unused)),
+ uint8_t protocol,
+ uint16_t port, sepol_security_id_t * out_sid)
+{
+ ocontext_t *c;
+ int rc = 0;
+
+ c = policydb->ocontexts[OCON_PORT];
+ while (c) {
+ if (c->u.port.protocol == protocol &&
+ c->u.port.low_port <= port && c->u.port.high_port >= port)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *out_sid = c->sid[0];
+ } else {
+ *out_sid = SECINITSID_PORT;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'. The `if_sid' SID is returned for
+ * the interface and the `msg_sid' SID is returned as
+ * the default SID for messages received on the
+ * interface.
+ */
+int hidden sepol_netif_sid(char *name,
+ sepol_security_id_t * if_sid,
+ sepol_security_id_t * msg_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_NETIF];
+ while (c) {
+ if (strcmp(name, c->u.name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0] || !c->sid[1]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[1],
+ &c->sid[1]);
+ if (rc)
+ goto out;
+ }
+ *if_sid = c->sid[0];
+ *msg_sid = c->sid[1];
+ } else {
+ *if_sid = SECINITSID_NETIF;
+ *msg_sid = SECINITSID_NETMSG;
+ }
+
+ out:
+ return rc;
+}
+
+static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
+ uint32_t * mask)
+{
+ int i, fail = 0;
+
+ for (i = 0; i < 4; i++)
+ if (addr[i] != (input[i] & mask[i])) {
+ fail = 1;
+ break;
+ }
+
+ return !fail;
+}
+
+/*
+ * Return the SID of the node specified by the address
+ * `addrp' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+int hidden sepol_node_sid(uint16_t domain,
+ void *addrp,
+ size_t addrlen, sepol_security_id_t * out_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ switch (domain) {
+ case AF_INET:{
+ uint32_t addr;
+
+ if (addrlen != sizeof(uint32_t)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ addr = *((uint32_t *) addrp);
+
+ c = policydb->ocontexts[OCON_NODE];
+ while (c) {
+ if (c->u.node.addr == (addr & c->u.node.mask))
+ break;
+ c = c->next;
+ }
+ break;
+ }
+
+ case AF_INET6:
+ if (addrlen != sizeof(uint64_t) * 2) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ c = policydb->ocontexts[OCON_NODE6];
+ while (c) {
+ if (match_ipv6_addrmask(addrp, c->u.node6.addr,
+ c->u.node6.mask))
+ break;
+ c = c->next;
+ }
+ break;
+
+ default:
+ *out_sid = SECINITSID_NODE;
+ goto out;
+ }
+
+ if (c) {
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *out_sid = c->sid[0];
+ } else {
+ *out_sid = SECINITSID_NODE;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated
+ * array containing the set of SIDs. Set `*nel' to the
+ * number of elements in the array.
+ */
+#define SIDS_NEL 25
+
+int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
+ char *username,
+ sepol_security_id_t ** sids, uint32_t * nel)
+{
+ context_struct_t *fromcon, usercon;
+ sepol_security_id_t *mysids, *mysids2, sid;
+ uint32_t mynel = 0, maxnel = SIDS_NEL;
+ user_datum_t *user;
+ role_datum_t *role;
+ struct sepol_av_decision avd;
+ int rc = 0;
+ unsigned int i, j, reason;
+ ebitmap_node_t *rnode, *tnode;
+
+ fromcon = sepol_sidtab_search(sidtab, fromsid);
+ if (!fromcon) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ user = (user_datum_t *) hashtab_search(policydb->p_users.table,
+ username);
+ if (!user) {
+ rc = -EINVAL;
+ goto out;
+ }
+ usercon.user = user->s.value;
+
+ mysids = malloc(maxnel * sizeof(sepol_security_id_t));
+ if (!mysids) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
+
+ ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
+ continue;
+ role = policydb->role_val_to_struct[i];
+ usercon.role = i + 1;
+ ebitmap_for_each_bit(&role->types.types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ usercon.type = j + 1;
+ if (usercon.type == fromcon->type)
+ continue;
+
+ if (mls_setup_user_range
+ (fromcon, user, &usercon, policydb->mls))
+ continue;
+
+ rc = context_struct_compute_av(fromcon, &usercon,
+ SECCLASS_PROCESS,
+ PROCESS__TRANSITION,
+ &avd, &reason);
+ if (rc || !(avd.allowed & PROCESS__TRANSITION))
+ continue;
+ rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
+ &sid);
+ if (rc) {
+ free(mysids);
+ goto out;
+ }
+ if (mynel < maxnel) {
+ mysids[mynel++] = sid;
+ } else {
+ maxnel += SIDS_NEL;
+ mysids2 =
+ malloc(maxnel *
+ sizeof(sepol_security_id_t));
+
+ if (!mysids2) {
+ rc = -ENOMEM;
+ free(mysids);
+ goto out;
+ }
+ memset(mysids2, 0,
+ maxnel * sizeof(sepol_security_id_t));
+ memcpy(mysids2, mysids,
+ mynel * sizeof(sepol_security_id_t));
+ free(mysids);
+ mysids = mysids2;
+ mysids[mynel++] = sid;
+ }
+ }
+ }
+
+ *sids = mysids;
+ *nel = mynel;
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+int hidden sepol_genfs_sid(const char *fstype,
+ char *path,
+ sepol_security_class_t sclass,
+ sepol_security_id_t * sid)
+{
+ size_t len;
+ genfs_t *genfs;
+ ocontext_t *c;
+ int rc = 0, cmp = 0;
+
+ for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
+ cmp = strcmp(fstype, genfs->fstype);
+ if (cmp <= 0)
+ break;
+ }
+
+ if (!genfs || cmp) {
+ *sid = SECINITSID_UNLABELED;
+ rc = -ENOENT;
+ goto out;
+ }
+
+ for (c = genfs->head; c; c = c->next) {
+ len = strlen(c->u.name);
+ if ((!c->v.sclass || sclass == c->v.sclass) &&
+ (strncmp(c->u.name, path, len) == 0))
+ break;
+ }
+
+ if (!c) {
+ *sid = SECINITSID_UNLABELED;
+ rc = -ENOENT;
+ goto out;
+ }
+
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0], &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+
+ *sid = c->sid[0];
+ out:
+ return rc;
+}
+
+int hidden sepol_fs_use(const char *fstype,
+ unsigned int *behavior, sepol_security_id_t * sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_FSUSE];
+ while (c) {
+ if (strcmp(fstype, c->u.name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ *behavior = c->v.behavior;
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *sid = c->sid[0];
+ } else {
+ rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+ if (rc) {
+ *behavior = SECURITY_FS_USE_NONE;
+ rc = 0;
+ } else {
+ *behavior = SECURITY_FS_USE_GENFS;
+ }
+ }
+
+ out:
+ return rc;
+}
+
+/* FLASK */
diff --git a/src/sidtab.c b/src/sidtab.c
new file mode 100644
index 0000000..5bd7999
--- /dev/null
+++ b/src/sidtab.c
@@ -0,0 +1,328 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the SID table type.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <sepol/policydb/sidtab.h>
+
+#include <sepol/policydb/flask.h>
+
+#define SIDTAB_HASH(sid) \
+(sid & SIDTAB_HASH_MASK)
+
+#define INIT_SIDTAB_LOCK(s)
+#define SIDTAB_LOCK(s)
+#define SIDTAB_UNLOCK(s)
+
+int sepol_sidtab_init(sidtab_t * s)
+{
+ int i;
+
+ s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE);
+ if (!s->htable)
+ return -ENOMEM;
+ for (i = 0; i < SIDTAB_SIZE; i++)
+ s->htable[i] = (sidtab_ptr_t) NULL;
+ s->nel = 0;
+ s->next_sid = 1;
+ s->shutdown = 0;
+ INIT_SIDTAB_LOCK(s);
+ return 0;
+}
+
+int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid,
+ context_struct_t * context)
+{
+ int hvalue;
+ sidtab_node_t *prev, *cur, *newnode;
+
+ if (!s || !s->htable)
+ return -ENOMEM;
+
+ hvalue = SIDTAB_HASH(sid);
+ prev = NULL;
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && sid == cur->sid) {
+ errno = EEXIST;
+ return -EEXIST;
+ }
+
+ newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t));
+ if (newnode == NULL)
+ return -ENOMEM;
+ newnode->sid = sid;
+ if (context_cpy(&newnode->context, context)) {
+ free(newnode);
+ return -ENOMEM;
+ }
+
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = s->htable[hvalue];
+ s->htable[hvalue] = newnode;
+ }
+
+ s->nel++;
+ if (sid >= s->next_sid)
+ s->next_sid = sid + 1;
+ return 0;
+}
+
+int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid)
+{
+ int hvalue;
+ sidtab_node_t *cur, *last;
+
+ if (!s || !s->htable)
+ return -ENOENT;
+
+ hvalue = SIDTAB_HASH(sid);
+ last = NULL;
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid) {
+ last = cur;
+ cur = cur->next;
+ }
+
+ if (cur == NULL || sid != cur->sid)
+ return -ENOENT;
+
+ if (last == NULL)
+ s->htable[hvalue] = cur->next;
+ else
+ last->next = cur->next;
+
+ context_destroy(&cur->context);
+
+ free(cur);
+ s->nel--;
+ return 0;
+}
+
+context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid)
+{
+ int hvalue;
+ sidtab_node_t *cur;
+
+ if (!s || !s->htable)
+ return NULL;
+
+ hvalue = SIDTAB_HASH(sid);
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid)
+ cur = cur->next;
+
+ if (cur == NULL || sid != cur->sid) {
+ /* Remap invalid SIDs to the unlabeled SID. */
+ sid = SECINITSID_UNLABELED;
+ hvalue = SIDTAB_HASH(sid);
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid)
+ cur = cur->next;
+ if (!cur || sid != cur->sid)
+ return NULL;
+ }
+
+ return &cur->context;
+}
+
+int sepol_sidtab_map(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args)
+{
+ int i, ret;
+ sidtab_node_t *cur;
+
+ if (!s || !s->htable)
+ return 0;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->sid, &cur->context, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args)
+{
+ int i, ret;
+ sidtab_node_t *last, *cur, *temp;
+
+ if (!s || !s->htable)
+ return;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ last = NULL;
+ cur = s->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->sid, &cur->context, args);
+ if (ret) {
+ if (last) {
+ last->next = cur->next;
+ } else {
+ s->htable[i] = cur->next;
+ }
+
+ temp = cur;
+ cur = cur->next;
+ context_destroy(&temp->context);
+ free(temp);
+ s->nel--;
+ } else {
+ last = cur;
+ cur = cur->next;
+ }
+ }
+ }
+
+ return;
+}
+
+static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s,
+ context_struct_t *
+ context)
+{
+ int i;
+ sidtab_node_t *cur;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ if (context_cmp(&cur->context, context))
+ return cur->sid;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+int sepol_sidtab_context_to_sid(sidtab_t * s,
+ context_struct_t * context,
+ sepol_security_id_t * out_sid)
+{
+ sepol_security_id_t sid;
+ int ret = 0;
+
+ *out_sid = SEPOL_SECSID_NULL;
+
+ sid = sepol_sidtab_search_context(s, context);
+ if (!sid) {
+ SIDTAB_LOCK(s);
+ /* Rescan now that we hold the lock. */
+ sid = sepol_sidtab_search_context(s, context);
+ if (sid)
+ goto unlock_out;
+ /* No SID exists for the context. Allocate a new one. */
+ if (s->next_sid == UINT_MAX || s->shutdown) {
+ ret = -ENOMEM;
+ goto unlock_out;
+ }
+ sid = s->next_sid++;
+ ret = sepol_sidtab_insert(s, sid, context);
+ if (ret)
+ s->next_sid--;
+ unlock_out:
+ SIDTAB_UNLOCK(s);
+ }
+
+ if (ret)
+ return ret;
+
+ *out_sid = sid;
+ return 0;
+}
+
+void sepol_sidtab_hash_eval(sidtab_t * h, char *tag)
+{
+ int i, chain_len, slots_used, max_chain_len;
+ sidtab_node_t *cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len);
+}
+
+void sepol_sidtab_destroy(sidtab_t * s)
+{
+ int i;
+ sidtab_ptr_t cur, temp;
+
+ if (!s || !s->htable)
+ return;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ context_destroy(&temp->context);
+ free(temp);
+ }
+ s->htable[i] = NULL;
+ }
+ free(s->htable);
+ s->htable = NULL;
+ s->nel = 0;
+ s->next_sid = 1;
+}
+
+void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src)
+{
+ SIDTAB_LOCK(src);
+ dst->htable = src->htable;
+ dst->nel = src->nel;
+ dst->next_sid = src->next_sid;
+ dst->shutdown = 0;
+ SIDTAB_UNLOCK(src);
+}
+
+void sepol_sidtab_shutdown(sidtab_t * s)
+{
+ SIDTAB_LOCK(s);
+ s->shutdown = 1;
+ SIDTAB_UNLOCK(s);
+}
+
+/* FLASK */
diff --git a/src/symtab.c b/src/symtab.c
new file mode 100644
index 0000000..b3a7aa8
--- /dev/null
+++ b/src/symtab.c
@@ -0,0 +1,49 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the symbol table type.
+ */
+
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/symtab.h>
+
+static unsigned int symhash(hashtab_t h, hashtab_key_t key)
+{
+ char *p, *keyp;
+ size_t size;
+ unsigned int val;
+
+ val = 0;
+ keyp = (char *)key;
+ size = strlen(keyp);
+ for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+ val =
+ (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+ return val & (h->size - 1);
+}
+
+static int symcmp(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ char *keyp1, *keyp2;
+
+ keyp1 = (char *)key1;
+ keyp2 = (char *)key2;
+ return strcmp(keyp1, keyp2);
+}
+
+int symtab_init(symtab_t * s, unsigned int size)
+{
+ s->table = hashtab_create(symhash, symcmp, size);
+ if (!s->table)
+ return -1;
+ s->nprim = 0;
+ return 0;
+}
+
+/* FLASK */
diff --git a/src/user_internal.h b/src/user_internal.h
new file mode 100644
index 0000000..7523b7d
--- /dev/null
+++ b/src/user_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_USER_INTERNAL_H_
+#define _SEPOL_USER_INTERNAL_H_
+
+#include <sepol/user_record.h>
+#include <sepol/users.h>
+#include "dso.h"
+
+hidden_proto(sepol_user_add_role)
+ hidden_proto(sepol_user_create)
+ hidden_proto(sepol_user_free)
+ hidden_proto(sepol_user_get_mlslevel)
+ hidden_proto(sepol_user_get_mlsrange)
+ hidden_proto(sepol_user_get_roles)
+ hidden_proto(sepol_user_has_role)
+ hidden_proto(sepol_user_key_create)
+ hidden_proto(sepol_user_key_unpack)
+ hidden_proto(sepol_user_set_mlslevel)
+ hidden_proto(sepol_user_set_mlsrange)
+ hidden_proto(sepol_user_set_name)
+#endif
diff --git a/src/user_record.c b/src/user_record.c
new file mode 100644
index 0000000..c59c54b
--- /dev/null
+++ b/src/user_record.c
@@ -0,0 +1,379 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "user_internal.h"
+#include "debug.h"
+
+struct sepol_user {
+ /* This user's name */
+ char *name;
+
+ /* This user's mls level (only required for mls) */
+ char *mls_level;
+
+ /* This user's mls range (only required for mls) */
+ char *mls_range;
+
+ /* The role array */
+ char **roles;
+
+ /* The number of roles */
+ unsigned int num_roles;
+};
+
+struct sepol_user_key {
+ /* This user's name */
+ const char *name;
+};
+
+int sepol_user_key_create(sepol_handle_t * handle,
+ const char *name, sepol_user_key_t ** key_ptr)
+{
+
+ sepol_user_key_t *tmp_key =
+ (sepol_user_key_t *) malloc(sizeof(sepol_user_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, "
+ "could not create selinux user key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_key_create)
+
+void sepol_user_key_unpack(const sepol_user_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_user_key_unpack)
+
+int sepol_user_key_extract(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_key_t ** key_ptr)
+{
+
+ if (sepol_user_key_create(handle, user->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from user %s", user->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_user_key_free(sepol_user_key_t * key)
+{
+ free(key);
+}
+
+int sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key)
+{
+
+ return strcmp(user->name, key->name);
+}
+
+int sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2)
+{
+
+ return strcmp(user->name, user2->name);
+}
+
+/* Name */
+const char *sepol_user_get_name(const sepol_user_t * user)
+{
+
+ return user->name;
+}
+
+int sepol_user_set_name(sepol_handle_t * handle,
+ sepol_user_t * user, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, could not set name");
+ return STATUS_ERR;
+ }
+ free(user->name);
+ user->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_name)
+
+/* MLS */
+const char *sepol_user_get_mlslevel(const sepol_user_t * user)
+{
+
+ return user->mls_level;
+}
+
+hidden_def(sepol_user_get_mlslevel)
+
+int sepol_user_set_mlslevel(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_level)
+{
+
+ char *tmp_mls_level = strdup(mls_level);
+ if (!tmp_mls_level) {
+ ERR(handle, "out of memory, "
+ "could not set MLS default level");
+ return STATUS_ERR;
+ }
+ free(user->mls_level);
+ user->mls_level = tmp_mls_level;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlslevel)
+
+const char *sepol_user_get_mlsrange(const sepol_user_t * user)
+{
+
+ return user->mls_range;
+}
+
+hidden_def(sepol_user_get_mlsrange)
+
+int sepol_user_set_mlsrange(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_range)
+{
+
+ char *tmp_mls_range = strdup(mls_range);
+ if (!tmp_mls_range) {
+ ERR(handle, "out of memory, "
+ "could not set MLS allowed range");
+ return STATUS_ERR;
+ }
+ free(user->mls_range);
+ user->mls_range = tmp_mls_range;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlsrange)
+
+/* Roles */
+int sepol_user_get_num_roles(const sepol_user_t * user)
+{
+
+ return user->num_roles;
+}
+
+int sepol_user_add_role(sepol_handle_t * handle,
+ sepol_user_t * user, const char *role)
+{
+
+ char *role_cp;
+ char **roles_realloc;
+
+ if (sepol_user_has_role(user, role))
+ return STATUS_SUCCESS;
+
+ role_cp = strdup(role);
+ roles_realloc = realloc(user->roles,
+ sizeof(char *) * (user->num_roles + 1));
+
+ if (!role_cp || !roles_realloc)
+ goto omem;
+
+ user->num_roles++;
+ user->roles = roles_realloc;
+ user->roles[user->num_roles - 1] = role_cp;
+
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not add role %s", role);
+ free(role_cp);
+ free(roles_realloc);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_user_add_role)
+
+int sepol_user_has_role(const sepol_user_t * user, const char *role)
+{
+
+ unsigned int i;
+
+ for (i = 0; i < user->num_roles; i++)
+ if (!strcmp(user->roles[i], role))
+ return 1;
+ return 0;
+}
+
+hidden_def(sepol_user_has_role)
+
+int sepol_user_set_roles(sepol_handle_t * handle,
+ sepol_user_t * user,
+ const char **roles_arr, unsigned int num_roles)
+{
+
+ unsigned int i;
+ char **tmp_roles = NULL;
+
+ if (num_roles > 0) {
+
+ /* First, make a copy */
+ tmp_roles = (char **)calloc(1, sizeof(char *) * num_roles);
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < num_roles; i++) {
+ tmp_roles[i] = strdup(roles_arr[i]);
+ if (!tmp_roles[i])
+ goto omem;
+ }
+ }
+
+ /* Apply other changes */
+ for (i = 0; i < user->num_roles; i++)
+ free(user->roles[i]);
+ free(user->roles);
+ user->roles = tmp_roles;
+ user->num_roles = num_roles;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not allocate roles array for"
+ "user %s", user->name);
+
+ if (tmp_roles) {
+ for (i = 0; i < num_roles; i++) {
+ if (!tmp_roles[i])
+ break;
+ free(tmp_roles[i]);
+ }
+ }
+ free(tmp_roles);
+ return STATUS_ERR;
+}
+
+int sepol_user_get_roles(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ const char ***roles_arr, unsigned int *num_roles)
+{
+
+ unsigned int i;
+ const char **tmp_roles =
+ (const char **)malloc(sizeof(char *) * user->num_roles);
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < user->num_roles; i++)
+ tmp_roles[i] = user->roles[i];
+
+ *roles_arr = tmp_roles;
+ *num_roles = user->num_roles;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not "
+ "allocate roles array for user %s", user->name);
+ free(tmp_roles);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_user_get_roles)
+
+void sepol_user_del_role(sepol_user_t * user, const char *role)
+{
+
+ unsigned int i;
+ for (i = 0; i < user->num_roles; i++) {
+ if (!strcmp(user->roles[i], role)) {
+ free(user->roles[i]);
+ user->roles[i] = NULL;
+ user->roles[i] = user->roles[user->num_roles - 1];
+ user->num_roles--;
+ }
+ }
+}
+
+/* Create */
+int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr)
+{
+
+ sepol_user_t *user = (sepol_user_t *) malloc(sizeof(sepol_user_t));
+
+ if (!user) {
+ ERR(handle, "out of memory, "
+ "could not create selinux user record");
+ return STATUS_ERR;
+ }
+
+ user->roles = NULL;
+ user->num_roles = 0;
+ user->name = NULL;
+ user->mls_level = NULL;
+ user->mls_range = NULL;
+
+ *user_ptr = user;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_create)
+
+/* Deep copy clone */
+int sepol_user_clone(sepol_handle_t * handle,
+ const sepol_user_t * user, sepol_user_t ** user_ptr)
+{
+
+ sepol_user_t *new_user = NULL;
+ unsigned int i;
+
+ if (sepol_user_create(handle, &new_user) < 0)
+ goto err;
+
+ if (sepol_user_set_name(handle, new_user, user->name) < 0)
+ goto err;
+
+ for (i = 0; i < user->num_roles; i++) {
+ if (sepol_user_add_role(handle, new_user, user->roles[i]) < 0)
+ goto err;
+ }
+
+ if (user->mls_level &&
+ (sepol_user_set_mlslevel(handle, new_user, user->mls_level) < 0))
+ goto err;
+
+ if (user->mls_range &&
+ (sepol_user_set_mlsrange(handle, new_user, user->mls_range) < 0))
+ goto err;
+
+ *user_ptr = new_user;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone selinux user record");
+ sepol_user_free(new_user);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_user_free(sepol_user_t * user)
+{
+
+ unsigned int i;
+
+ if (!user)
+ return;
+
+ free(user->name);
+ for (i = 0; i < user->num_roles; i++)
+ free(user->roles[i]);
+ free(user->roles);
+ free(user->mls_level);
+ free(user->mls_range);
+ free(user);
+}
+
+hidden_def(sepol_user_free)
diff --git a/src/users.c b/src/users.c
new file mode 100644
index 0000000..693210d
--- /dev/null
+++ b/src/users.c
@@ -0,0 +1,383 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "private.h"
+#include "debug.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include "user_internal.h"
+#include "mls.h"
+
+static int user_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ int user_idx, sepol_user_t ** record)
+{
+
+ const char *name = policydb->p_user_val_to_name[user_idx];
+ user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx];
+ ebitmap_t *roles = &(usrdatum->roles.roles);
+ ebitmap_node_t *rnode;
+ unsigned bit;
+
+ sepol_user_t *tmp_record = NULL;
+
+ if (sepol_user_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_user_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ /* Extract roles */
+ ebitmap_for_each_bit(roles, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit)) {
+ char *role = policydb->p_role_val_to_name[bit];
+ if (sepol_user_add_role(handle, tmp_record, role) < 0)
+ goto err;
+ }
+ }
+
+ /* Extract MLS info */
+ if (policydb->mls) {
+ context_struct_t context;
+ char *str;
+
+ context_init(&context);
+ if (mls_level_cpy(&context.range.level[0],
+ &usrdatum->exp_dfltlevel) < 0) {
+ ERR(handle, "could not copy MLS level");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_level_cpy(&context.range.level[1],
+ &usrdatum->exp_dfltlevel) < 0) {
+ ERR(handle, "could not copy MLS level");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_to_string(handle, policydb, &context, &str) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) {
+ free(str);
+ goto err;
+ }
+ free(str);
+
+ context_init(&context);
+ if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) {
+ ERR(handle, "could not copy MLS range");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_to_string(handle, policydb, &context, &str) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) {
+ free(str);
+ goto err;
+ }
+ free(str);
+ }
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ /* FIXME: handle error */
+ sepol_user_free(tmp_record);
+ return STATUS_ERR;
+}
+
+int sepol_user_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_user_key_t * key, const sepol_user_t * user)
+{
+
+ policydb_t *policydb = &p->p;
+
+ /* For user data */
+ const char *cname, *cmls_level, *cmls_range;
+ char *name = NULL;
+
+ const char **roles = NULL;
+ unsigned int num_roles = 0;
+
+ /* Low-level representation */
+ user_datum_t *usrdatum = NULL;
+ role_datum_t *roldatum;
+ unsigned int i;
+
+ context_struct_t context;
+ unsigned bit;
+ int new = 0;
+
+ ebitmap_node_t *rnode;
+
+ /* First, extract all the data */
+ sepol_user_key_unpack(key, &cname);
+
+ cmls_level = sepol_user_get_mlslevel(user);
+ cmls_range = sepol_user_get_mlsrange(user);
+
+ /* Make sure that worked properly */
+ if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0)
+ goto err;
+
+ /* Now, see if a user exists */
+ usrdatum = hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname);
+
+ /* If it does, we will modify it */
+ if (usrdatum) {
+
+ int value_cp = usrdatum->s.value;
+ user_datum_destroy(usrdatum);
+ user_datum_init(usrdatum);
+ usrdatum->s.value = value_cp;
+
+ /* Otherwise, create a new one */
+ } else {
+ usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!usrdatum)
+ goto omem;
+ user_datum_init(usrdatum);
+ new = 1;
+ }
+
+ /* For every role */
+ for (i = 0; i < num_roles; i++) {
+
+ /* Search for the role */
+ roldatum = hashtab_search(policydb->p_roles.table,
+ (const hashtab_key_t)roles[i]);
+ if (!roldatum) {
+ ERR(handle, "undefined role %s for user %s",
+ roles[i], cname);
+ goto err;
+ }
+
+ /* Set the role and every role it dominates */
+ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit)) {
+ if (ebitmap_set_bit
+ (&(usrdatum->roles.roles), bit, 1))
+ goto omem;
+ }
+ }
+ }
+
+ /* For MLS systems */
+ if (policydb->mls) {
+
+ /* MLS level */
+ if (cmls_level == NULL) {
+ ERR(handle, "MLS is enabled, but no MLS "
+ "default level was defined for user %s", cname);
+ goto err;
+ }
+
+ context_init(&context);
+ if (mls_from_string(handle, policydb, cmls_level, &context) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_level_cpy(&usrdatum->exp_dfltlevel,
+ &context.range.level[0]) < 0) {
+ ERR(handle, "could not copy MLS level %s", cmls_level);
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ /* MLS range */
+ if (cmls_range == NULL) {
+ ERR(handle, "MLS is enabled, but no MLS"
+ "range was defined for user %s", cname);
+ goto err;
+ }
+
+ context_init(&context);
+ if (mls_from_string(handle, policydb, cmls_range, &context) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) {
+ ERR(handle, "could not copy MLS range %s", cmls_range);
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+ } else if (cmls_level != NULL || cmls_range != NULL) {
+ ERR(handle, "MLS is disabled, but MLS level/range "
+ "was found for user %s", cname);
+ goto err;
+ }
+
+ /* If there are no errors, and this is a new user, add the user to policy */
+ if (new) {
+ void *tmp_ptr;
+
+ /* Ensure reverse lookup array has enough space */
+ tmp_ptr = realloc(policydb->user_val_to_struct,
+ (policydb->p_users.nprim +
+ 1) * sizeof(user_datum_t *));
+ if (!tmp_ptr)
+ goto omem;
+ policydb->user_val_to_struct = tmp_ptr;
+
+ tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS],
+ (policydb->p_users.nprim +
+ 1) * sizeof(char *));
+ if (!tmp_ptr)
+ goto omem;
+ policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
+
+ /* Need to copy the user name */
+ name = strdup(cname);
+ if (!name)
+ goto omem;
+
+ /* Store user */
+ usrdatum->s.value = ++policydb->p_users.nprim;
+ if (hashtab_insert(policydb->p_users.table, name,
+ (hashtab_datum_t) usrdatum) < 0)
+ goto omem;
+
+ /* Set up reverse entry */
+ policydb->p_user_val_to_name[usrdatum->s.value - 1] = name;
+ policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+ name = NULL;
+
+ /* Expand roles */
+ if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
+ policydb, NULL, NULL)) {
+ ERR(handle, "unable to expand role set");
+ goto err;
+ }
+ }
+
+ free(roles);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not load %s into policy", name);
+
+ free(name);
+ free(roles);
+ if (new && usrdatum) {
+ role_set_destroy(&usrdatum->roles);
+ free(usrdatum);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+
+ const char *cname;
+ sepol_user_key_unpack(key, &cname);
+
+ *response = (hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname) != NULL);
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ *response = policydb->p_users.nprim;
+
+ handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+int sepol_user_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key, sepol_user_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ user_datum_t *usrdatum = NULL;
+
+ const char *cname;
+ sepol_user_key_unpack(key, &cname);
+
+ usrdatum = hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname);
+
+ if (!usrdatum) {
+ *response = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) <
+ 0)
+ goto err;
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query user %s", cname);
+ return STATUS_ERR;
+}
+
+int sepol_user_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_user_t * user,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ unsigned int nusers = policydb->p_users.nprim;
+ sepol_user_t *user = NULL;
+ unsigned int i;
+
+ /* For each user */
+ for (i = 0; i < nusers; i++) {
+
+ int status;
+
+ if (user_to_record(handle, policydb, i, &user) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(user, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_user_free(user);
+ user = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over users");
+ sepol_user_free(user);
+ return STATUS_ERR;
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..a824e61
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,116 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005-2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+
+struct val_to_name {
+ unsigned int val;
+ char *name;
+};
+
+/* Add an unsigned integer to a dynamically reallocated array. *cnt
+ * is a reference pointer to the number of values already within array
+ * *a; it will be incremented upon successfully appending i. If *a is
+ * NULL then this function will create a new array (*cnt is reset to
+ * 0). Return 0 on success, -1 on out of memory. */
+int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
+{
+ if (cnt == NULL || a == NULL)
+ return -1;
+
+ /* FIX ME: This is not very elegant! We use an array that we
+ * grow as new uint32_t are added to an array. But rather
+ * than be smart about it, for now we realloc() the array each
+ * time a new uint32_t is added! */
+ if (*a != NULL)
+ *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
+ else { /* empty list */
+
+ *cnt = 0;
+ *a = (uint32_t *) malloc(sizeof(uint32_t));
+ }
+ if (*a == NULL) {
+ return -1;
+ }
+ (*a)[*cnt] = i;
+ (*cnt)++;
+ return 0;
+}
+
+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ struct val_to_name *v = data;
+ perm_datum_t *perdatum;
+
+ perdatum = (perm_datum_t *) datum;
+
+ if (v->val == perdatum->s.value) {
+ v->name = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+ sepol_access_vector_t av)
+{
+ struct val_to_name v;
+ static char avbuf[1024];
+ class_datum_t *cladatum;
+ char *perm = NULL, *p;
+ unsigned int i;
+ int rc;
+ int avlen = 0, len;
+
+ cladatum = policydbp->class_val_to_struct[tclass - 1];
+ p = avbuf;
+ for (i = 0; i < cladatum->permissions.nprim; i++) {
+ if (av & (1 << i)) {
+ v.val = i + 1;
+ rc = hashtab_map(cladatum->permissions.table,
+ perm_name, &v);
+ if (!rc && cladatum->comdatum) {
+ rc = hashtab_map(cladatum->comdatum->
+ permissions.table, perm_name,
+ &v);
+ }
+ if (rc)
+ perm = v.name;
+ if (perm) {
+ len =
+ snprintf(p, sizeof(avbuf) - avlen, " %s",
+ perm);
+ if (len < 0
+ || (size_t) len >= (sizeof(avbuf) - avlen))
+ return NULL;
+ p += len;
+ avlen += len;
+ }
+ }
+ }
+
+ return avbuf;
+}
diff --git a/src/write.c b/src/write.c
new file mode 100644
index 0000000..290e036
--- /dev/null
+++ b/src/write.c
@@ -0,0 +1,2009 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org>
+ *
+ * Module writing support
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask.h>
+
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+struct policy_data {
+ struct policy_file *fp;
+ struct policydb *p;
+};
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp);
+
+static int ebitmap_write(ebitmap_t * e, struct policy_file *fp)
+{
+ ebitmap_node_t *n;
+ uint32_t buf[32], bit, count;
+ uint64_t map;
+ size_t items;
+
+ buf[0] = cpu_to_le32(MAPSIZE);
+ buf[1] = cpu_to_le32(e->highbit);
+
+ count = 0;
+ for (n = e->node; n; n = n->next)
+ count++;
+ buf[2] = cpu_to_le32(count);
+
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+
+ for (n = e->node; n; n = n->next) {
+ bit = cpu_to_le32(n->startbit);
+ items = put_entry(&bit, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ map = cpu_to_le64(n->map);
+ items = put_entry(&map, sizeof(uint64_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+ AVTAB_ALLOWED,
+ AVTAB_AUDITDENY,
+ AVTAB_AUDITALLOW,
+ AVTAB_TRANSITION,
+ AVTAB_CHANGE,
+ AVTAB_MEMBER
+};
+
+static int avtab_write_item(policydb_t * p,
+ avtab_ptr_t cur, struct policy_file *fp,
+ unsigned merge, unsigned commit, uint32_t * nel)
+{
+ avtab_ptr_t node;
+ uint16_t buf16[4];
+ uint32_t buf32[10], lookup, val;
+ size_t items, items2;
+ unsigned set;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+ unsigned int i;
+
+ if (oldvers) {
+ /* Generate the old avtab format.
+ Requires merging similar entries if uncond avtab. */
+ if (merge) {
+ if (cur->merged)
+ return POLICYDB_SUCCESS; /* already merged by prior merge */
+ }
+
+ items = 1; /* item 0 is used for the item count */
+ val = cur->key.source_type;
+ buf32[items++] = cpu_to_le32(val);
+ val = cur->key.target_type;
+ buf32[items++] = cpu_to_le32(val);
+ val = cur->key.target_class;
+ buf32[items++] = cpu_to_le32(val);
+
+ val = cur->key.specified & ~AVTAB_ENABLED;
+ if (cur->key.specified & AVTAB_ENABLED)
+ val |= AVTAB_ENABLED_OLD;
+ set = 1;
+
+ if (merge) {
+ /* Merge specifier values for all similar (av or type)
+ entries that have the same key. */
+ if (val & AVTAB_AV)
+ lookup = AVTAB_AV;
+ else if (val & AVTAB_TYPE)
+ lookup = AVTAB_TYPE;
+ else
+ return POLICYDB_ERROR;
+ for (node = avtab_search_node_next(cur, lookup);
+ node;
+ node = avtab_search_node_next(node, lookup)) {
+ val |= (node->key.specified & ~AVTAB_ENABLED);
+ set++;
+ if (node->key.specified & AVTAB_ENABLED)
+ val |= AVTAB_ENABLED_OLD;
+ }
+ }
+
+ if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+ ERR(fp->handle, "null entry");
+ return POLICYDB_ERROR;
+ }
+ if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+ ERR(fp->handle, "entry has both access "
+ "vectors and types");
+ return POLICYDB_ERROR;
+ }
+
+ buf32[items++] = cpu_to_le32(val);
+
+ if (merge) {
+ /* Include datums for all similar (av or type)
+ entries that have the same key. */
+ for (i = 0;
+ i < (sizeof(spec_order) / sizeof(spec_order[0]));
+ i++) {
+ if (val & spec_order[i]) {
+ if (cur->key.specified & spec_order[i])
+ node = cur;
+ else {
+ node =
+ avtab_search_node_next(cur,
+ spec_order
+ [i]);
+ if (nel)
+ (*nel)--; /* one less node */
+ }
+
+ if (!node) {
+ ERR(fp->handle, "missing node");
+ return POLICYDB_ERROR;
+ }
+ buf32[items++] =
+ cpu_to_le32(node->datum.data);
+ set--;
+ node->merged = 1;
+ }
+ }
+ } else {
+ buf32[items++] = cpu_to_le32(cur->datum.data);
+ cur->merged = 1;
+ set--;
+ }
+
+ if (set) {
+ ERR(fp->handle, "data count wrong");
+ return POLICYDB_ERROR;
+ }
+
+ buf32[0] = cpu_to_le32(items - 1);
+
+ if (commit) {
+ /* Commit this item to the policy file. */
+ items2 = put_entry(buf32, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+ }
+
+ /* Generate the new avtab format. */
+ buf16[0] = cpu_to_le16(cur->key.source_type);
+ buf16[1] = cpu_to_le16(cur->key.target_type);
+ buf16[2] = cpu_to_le16(cur->key.target_class);
+ buf16[3] = cpu_to_le16(cur->key.specified);
+ items = put_entry(buf16, sizeof(uint16_t), 4, fp);
+ if (items != 4)
+ return POLICYDB_ERROR;
+ buf32[0] = cpu_to_le32(cur->datum.data);
+ items = put_entry(buf32, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ return POLICYDB_SUCCESS;
+}
+
+static inline void avtab_reset_merged(avtab_t * a)
+{
+ unsigned int i;
+ avtab_ptr_t cur;
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next)
+ cur->merged = 0;
+ }
+}
+
+static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
+{
+ unsigned int i;
+ int rc;
+ avtab_t expa;
+ avtab_ptr_t cur;
+ uint32_t nel;
+ size_t items;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+
+ if (oldvers) {
+ /* Old avtab format.
+ First, we need to expand attributes. Then, we need to
+ merge similar entries, so we need to track merged nodes
+ and compute the final nel. */
+ if (avtab_init(&expa))
+ return POLICYDB_ERROR;
+ if (expand_avtab(p, a, &expa)) {
+ rc = -1;
+ goto out;
+ }
+ a = &expa;
+ avtab_reset_merged(a);
+ nel = a->nel;
+ } else {
+ /* New avtab format. nel is good to go. */
+ nel = cpu_to_le32(a->nel);
+ items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ /* If old format, compute final nel.
+ If new format, write out the items. */
+ if (avtab_write_item(p, cur, fp, 1, !oldvers, &nel)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ }
+
+ if (oldvers) {
+ /* Old avtab format.
+ Write the computed nel value, then write the items. */
+ nel = cpu_to_le32(nel);
+ items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+ if (items != 1) {
+ rc = -1;
+ goto out;
+ }
+ avtab_reset_merged(a);
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ }
+ }
+
+ rc = 0;
+ out:
+ if (oldvers)
+ avtab_destroy(&expa);
+ return rc;
+}
+
+/*
+ * Write a semantic MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_semantic_level_helper(mls_semantic_level_t * l,
+ struct policy_file *fp)
+{
+ uint32_t buf[2], ncat = 0;
+ size_t items;
+ mls_semantic_cat_t *cat;
+
+ for (cat = l->cat; cat; cat = cat->next)
+ ncat++;
+
+ buf[0] = cpu_to_le32(l->sens);
+ buf[1] = cpu_to_le32(ncat);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+
+ for (cat = l->cat; cat; cat = cat->next) {
+ buf[0] = cpu_to_le32(cat->low);
+ buf[1] = cpu_to_le32(cat->high);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Read a semantic MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_semantic_range_helper(mls_semantic_range_t * r,
+ struct policy_file *fp)
+{
+ int rc;
+
+ rc = mls_write_semantic_level_helper(&r->level[0], fp);
+ if (rc)
+ return rc;
+
+ rc = mls_write_semantic_level_helper(&r->level[1], fp);
+
+ return rc;
+}
+
+/*
+ * Write a MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_level(mls_level_t * l, struct policy_file *fp)
+{
+ uint32_t sens;
+ size_t items;
+
+ sens = cpu_to_le32(l->sens);
+ items = put_entry(&sens, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&l->cat, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+ uint32_t buf[3];
+ size_t items, items2;
+ int eq;
+
+ eq = mls_level_eq(&r->level[1], &r->level[0]);
+
+ items = 1; /* item 0 is used for the item count */
+ buf[items++] = cpu_to_le32(r->level[0].sens);
+ if (!eq)
+ buf[items++] = cpu_to_le32(r->level[1].sens);
+ buf[0] = cpu_to_le32(items - 1);
+
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&r->level[0].cat, fp))
+ return POLICYDB_ERROR;
+ if (!eq)
+ if (ebitmap_write(&r->level[1].cat, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ level_datum_t *levdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ levdatum = (level_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(levdatum->isalias);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (mls_write_level(levdatum->level, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ cat_datum_t *catdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ catdatum = (cat_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(catdatum->s.value);
+ buf[items++] = cpu_to_le32(catdatum->isalias);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_trans_write(policydb_t *p, struct policy_file *fp)
+{
+ role_trans_t *r = p->role_tr;
+ role_trans_t *tr;
+ uint32_t buf[3];
+ size_t nel, items;
+ int new_roletr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+ int warning_issued = 0;
+
+ nel = 0;
+ for (tr = r; tr; tr = tr->next)
+ if(new_roletr || tr->tclass == SECCLASS_PROCESS)
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (tr = r; tr; tr = tr->next) {
+ if (!new_roletr && tr->tclass != SECCLASS_PROCESS) {
+ if (!warning_issued)
+ WARN(fp->handle, "Discarding role_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warning_issued = 1;
+ continue;
+ }
+ buf[0] = cpu_to_le32(tr->role);
+ buf[1] = cpu_to_le32(tr->type);
+ buf[2] = cpu_to_le32(tr->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+ if (new_roletr) {
+ buf[0] = cpu_to_le32(tr->tclass);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_allow_write(role_allow_t * r, struct policy_file *fp)
+{
+ role_allow_t *ra;
+ uint32_t buf[2];
+ size_t nel, items;
+
+ nel = 0;
+ for (ra = r; ra; ra = ra->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ra = r; ra; ra = ra->next) {
+ buf[0] = cpu_to_le32(ra->role);
+ buf[1] = cpu_to_le32(ra->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_write(filename_trans_t * r, struct policy_file *fp)
+{
+ filename_trans_t *ft;
+ uint32_t buf[4];
+ size_t nel, items, len;
+
+ nel = 0;
+ for (ft = r; ft; ft = ft->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ft = r; ft; ft = ft->next) {
+ len = strlen(ft->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ items = put_entry(ft->name, sizeof(char), len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(ft->stype);
+ buf[1] = cpu_to_le32(ft->ttype);
+ buf[2] = cpu_to_le32(ft->tclass);
+ buf[3] = cpu_to_le32(ft->otype);
+ items = put_entry(buf, sizeof(uint32_t), 4, fp);
+ if (items != 4)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_set_write(role_set_t * x, struct policy_file *fp)
+{
+ size_t items;
+ uint32_t buf[1];
+
+ if (ebitmap_write(&x->roles, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(x->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int type_set_write(type_set_t * x, struct policy_file *fp)
+{
+ size_t items;
+ uint32_t buf[1];
+
+ if (ebitmap_write(&x->types, fp))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&x->negset, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(x->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ cond_bool_datum_t *booldatum;
+ uint32_t buf[3], len;
+ unsigned int items, items2;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ booldatum = (cond_bool_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(booldatum->s.value);
+ buf[items++] = cpu_to_le32(booldatum->state);
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * cond_write_cond_av_list doesn't write out the av_list nodes.
+ * Instead it writes out the key/value pairs from the avtab. This
+ * is necessary because there is no way to uniquely identifying rules
+ * in the avtab so it is not possible to associate individual rules
+ * in the avtab with a conditional without saving them as part of
+ * the conditional. This means that the avtab with the conditional
+ * rules will not be saved but will be rebuilt on policy load.
+ */
+static int cond_write_av_list(policydb_t * p,
+ cond_av_list_t * list, struct policy_file *fp)
+{
+ uint32_t buf[4];
+ cond_av_list_t *cur_list, *new_list = NULL;
+ avtab_t expa;
+ uint32_t len, items;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+ int rc = -1;
+
+ if (oldvers) {
+ if (avtab_init(&expa))
+ return POLICYDB_ERROR;
+ if (expand_cond_av_list(p, list, &new_list, &expa))
+ goto out;
+ list = new_list;
+ }
+
+ len = 0;
+ for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+ if (cur_list->node->parse_context)
+ len++;
+ }
+
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ goto out;
+
+ if (len == 0) {
+ rc = 0;
+ goto out;
+ }
+
+ for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+ if (cur_list->node->parse_context)
+ if (avtab_write_item(p, cur_list->node, fp, 0, 1, NULL))
+ goto out;
+ }
+
+ rc = 0;
+ out:
+ if (oldvers) {
+ cond_av_list_destroy(new_list);
+ avtab_destroy(&expa);
+ }
+
+ return rc;
+}
+
+static int cond_write_node(policydb_t * p,
+ cond_node_t * node, struct policy_file *fp)
+{
+ cond_expr_t *cur_expr;
+ uint32_t buf[2];
+ uint32_t items, items2, len;
+
+ buf[0] = cpu_to_le32(node->cur_state);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ /* expr */
+ len = 0;
+ for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
+ len++;
+
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
+ items = 0;
+ buf[items++] = cpu_to_le32(cur_expr->expr_type);
+ buf[items++] = cpu_to_le32(cur_expr->bool);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (cond_write_av_list(p, node->true_list, fp) != 0)
+ return POLICYDB_ERROR;
+ if (cond_write_av_list(p, node->false_list, fp) != 0)
+ return POLICYDB_ERROR;
+ } else {
+ if (avrule_write_list(node->avtrue_list, fp))
+ return POLICYDB_ERROR;
+ if (avrule_write_list(node->avfalse_list, fp))
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cond_write_list(policydb_t * p, cond_list_t * list,
+ struct policy_file *fp)
+{
+ cond_node_t *cur;
+ uint32_t len, items;
+ uint32_t buf[1];
+
+ len = 0;
+ for (cur = list; cur != NULL; cur = cur->next)
+ len++;
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (cur = list; cur != NULL; cur = cur->next) {
+ if (cond_write_node(p, cur, fp) != 0)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a security context structure
+ * to a policydb binary representation file.
+ */
+static int context_write(struct policydb *p, context_struct_t * c,
+ struct policy_file *fp)
+{
+ uint32_t buf[32];
+ size_t items, items2;
+
+ items = 0;
+ buf[items++] = cpu_to_le32(c->user);
+ buf[items++] = cpu_to_le32(c->role);
+ buf[items++] = cpu_to_le32(c->type);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_BASE))
+ if (mls_write_range_helper(&c->range, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * The following *_write functions are used to
+ * write the symbol data to a policy database
+ * binary representation file.
+ */
+
+static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ perm_datum_t *perdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ perdatum = (perm_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(perdatum->s.value);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ common_datum_t *comdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ comdatum = (common_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(comdatum->s.value);
+ buf[items++] = cpu_to_le32(comdatum->permissions.nprim);
+ buf[items++] = cpu_to_le32(comdatum->permissions.table->nel);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (hashtab_map(comdatum->permissions.table, perm_write, pd))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int write_cons_helper(policydb_t * p,
+ constraint_node_t * node, int allowxtarget,
+ struct policy_file *fp)
+{
+ constraint_node_t *c;
+ constraint_expr_t *e;
+ uint32_t buf[3], nexpr;
+ int items;
+
+ for (c = node; c; c = c->next) {
+ nexpr = 0;
+ for (e = c->expr; e; e = e->next) {
+ nexpr++;
+ }
+ buf[0] = cpu_to_le32(c->permissions);
+ buf[1] = cpu_to_le32(nexpr);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ for (e = c->expr; e; e = e->next) {
+ items = 0;
+ buf[0] = cpu_to_le32(e->expr_type);
+ buf[1] = cpu_to_le32(e->attr);
+ buf[2] = cpu_to_le32(e->op);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+
+ switch (e->expr_type) {
+ case CEXPR_NAMES:
+ if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&e->names, fp)) {
+ return POLICYDB_ERROR;
+ }
+ if (p->policy_type != POLICY_KERN &&
+ type_set_write(e->type_names, fp)) {
+ return POLICYDB_ERROR;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ class_datum_t *cladatum;
+ constraint_node_t *c;
+ uint32_t buf[32], ncons;
+ size_t items, items2, len, len2;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ cladatum = (class_datum_t *) datum;
+
+ len = strlen(key);
+ if (cladatum->comkey)
+ len2 = strlen(cladatum->comkey);
+ else
+ len2 = 0;
+
+ ncons = 0;
+ for (c = cladatum->constraints; c; c = c->next) {
+ ncons++;
+ }
+
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(len2);
+ buf[items++] = cpu_to_le32(cladatum->s.value);
+ buf[items++] = cpu_to_le32(cladatum->permissions.nprim);
+ if (cladatum->permissions.table)
+ buf[items++] = cpu_to_le32(cladatum->permissions.table->nel);
+ else
+ buf[items++] = 0;
+ buf[items++] = cpu_to_le32(ncons);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (cladatum->comkey) {
+ items = put_entry(cladatum->comkey, 1, len2, fp);
+ if (items != len2)
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(cladatum->permissions.table, perm_write, pd))
+ return POLICYDB_ERROR;
+
+ if (write_cons_helper(p, cladatum->constraints, 0, fp))
+ return POLICYDB_ERROR;
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+ /* write out the validatetrans rule */
+ ncons = 0;
+ for (c = cladatum->validatetrans; c; c = c->next) {
+ ncons++;
+ }
+ buf[0] = cpu_to_le32(ncons);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (write_cons_helper(p, cladatum->validatetrans, 1, fp))
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ role_datum_t *role;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ role = (role_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(role->s.value);
+ if (policydb_has_boundary_feature(p))
+ buf[items++] = cpu_to_le32(role->bounds);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&role->dominates, fp))
+ return POLICYDB_ERROR;
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&role->types.types, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (type_set_write(&role->types, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+ buf[0] = cpu_to_le32(role->flavor);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&role->roles, fp))
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ type_datum_t *typdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ typdatum = (type_datum_t *) datum;
+
+ /*
+ * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
+ * does not support to load entries of attribute, so we skip to write it.
+ */
+ if (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_BOUNDARY
+ && typdatum->flavor == TYPE_ATTRIB)
+ return POLICYDB_SUCCESS;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(typdatum->s.value);
+ if (policydb_has_boundary_feature(p)) {
+ uint32_t properties = 0;
+
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+ buf[items++] = cpu_to_le32(typdatum->primary);
+ }
+
+ if (typdatum->primary)
+ properties |= TYPEDATUM_PROPERTY_PRIMARY;
+
+ if (typdatum->flavor == TYPE_ATTRIB) {
+ properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+ } else if (typdatum->flavor == TYPE_ALIAS
+ && p->policy_type != POLICY_KERN)
+ properties |= TYPEDATUM_PROPERTY_ALIAS;
+
+ if (typdatum->flags & TYPE_FLAGS_PERMISSIVE
+ && p->policy_type != POLICY_KERN)
+ properties |= TYPEDATUM_PROPERTY_PERMISSIVE;
+
+ buf[items++] = cpu_to_le32(properties);
+ buf[items++] = cpu_to_le32(typdatum->bounds);
+ } else {
+ buf[items++] = cpu_to_le32(typdatum->primary);
+
+ if (p->policy_type != POLICY_KERN) {
+ buf[items++] = cpu_to_le32(typdatum->flavor);
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ buf[items++] = cpu_to_le32(typdatum->flags);
+ else if (typdatum->flags & TYPE_FLAGS_PERMISSIVE)
+ WARN(fp->handle, "Warning! Module policy "
+ "version %d cannot support permissive "
+ "types, but one was defined",
+ p->policyvers);
+ }
+ }
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type != POLICY_KERN) {
+ if (ebitmap_write(&typdatum->types, fp))
+ return POLICYDB_ERROR;
+ }
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ user_datum_t *usrdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ usrdatum = (user_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(usrdatum->s.value);
+ if (policydb_has_boundary_feature(p))
+ buf[items++] = cpu_to_le32(usrdatum->bounds);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&usrdatum->roles.roles, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (role_set_write(&usrdatum->roles, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_MOD)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_BASE)) {
+ if (mls_write_range_helper(&usrdatum->exp_range, fp))
+ return POLICYDB_ERROR;
+ if (mls_write_level(&usrdatum->exp_dfltlevel, fp))
+ return POLICYDB_ERROR;
+ } else if ((p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_MOD)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_BASE)) {
+ if (mls_write_semantic_range_helper(&usrdatum->range, fp))
+ return -1;
+ if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp))
+ return -1;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_write, class_write, role_write, type_write, user_write,
+ cond_write_bool, sens_write, cat_write,};
+
+static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p,
+ struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, items;
+ uint32_t buf[32];
+ ocontext_t *c;
+ for (i = 0; i < info->ocon_num; i++) {
+ nel = 0;
+ for (c = p->ocontexts[i]; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = p->ocontexts[i]; c; c = c->next) {
+ switch (i) {
+ case OCON_XEN_ISID:
+ buf[0] = cpu_to_le32(c->sid[0]);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_PIRQ:
+ buf[0] = cpu_to_le32(c->u.pirq);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_IOPORT:
+ buf[0] = c->u.ioport.low_ioport;
+ buf[1] = c->u.ioport.high_ioport;
+ for (j = 0; j < 2; j++)
+ buf[j] = cpu_to_le32(buf[j]);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_IOMEM:
+ buf[0] = c->u.iomem.low_iomem;
+ buf[1] = c->u.iomem.high_iomem;
+ for (j = 0; j < 2; j++)
+ buf[j] = cpu_to_le32(buf[j]);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ buf[0] = cpu_to_le32(c->u.device);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write_selinux(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, items, len;
+ uint32_t buf[32];
+ ocontext_t *c;
+ for (i = 0; i < info->ocon_num; i++) {
+ nel = 0;
+ for (c = p->ocontexts[i]; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = p->ocontexts[i]; c; c = c->next) {
+ switch (i) {
+ case OCON_ISID:
+ buf[0] = cpu_to_le32(c->sid[0]);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_FS:
+ case OCON_NETIF:
+ len = strlen(c->u.name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[1], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_PORT:
+ buf[0] = c->u.port.protocol;
+ buf[1] = c->u.port.low_port;
+ buf[2] = c->u.port.high_port;
+ for (j = 0; j < 3; j++) {
+ buf[j] = cpu_to_le32(buf[j]);
+ }
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_NODE:
+ buf[0] = c->u.node.addr; /* network order */
+ buf[1] = c->u.node.mask; /* network order */
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_FSUSE:
+ buf[0] = cpu_to_le32(c->v.behavior);
+ len = strlen(c->u.name);
+ buf[1] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_NODE6:
+ for (j = 0; j < 4; j++)
+ buf[j] = c->u.node6.addr[j]; /* network order */
+ for (j = 0; j < 4; j++)
+ buf[j + 4] = c->u.node6.mask[j]; /* network order */
+ items = put_entry(buf, sizeof(uint32_t), 8, fp);
+ if (items != 8)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write(struct policydb_compat_info *info, policydb_t * p,
+ struct policy_file *fp)
+{
+ int rc = POLICYDB_ERROR;
+ switch (p->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_write_selinux(info, p, fp);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_write_xen(info, p, fp);
+ break;
+ }
+ return rc;
+}
+
+static int genfs_write(policydb_t * p, struct policy_file *fp)
+{
+ genfs_t *genfs;
+ ocontext_t *c;
+ size_t nel = 0, items, len;
+ uint32_t buf[32];
+
+ for (genfs = p->genfs; genfs; genfs = genfs->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (genfs = p->genfs; genfs; genfs = genfs->next) {
+ len = strlen(genfs->fstype);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(genfs->fstype, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ nel = 0;
+ for (c = genfs->head; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = genfs->head; c; c = c->next) {
+ len = strlen(c->u.name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ buf[0] = cpu_to_le32(c->v.sclass);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int range_write(policydb_t * p, struct policy_file *fp)
+{
+ size_t nel, items;
+ struct range_trans *rt;
+ uint32_t buf[2];
+ int new_rangetr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+ int warning_issued = 0;
+
+ nel = 0;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ /* all range_transitions are written for the new format, only
+ process related range_transitions are written for the old
+ format, so count accordingly */
+ if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
+ nel++;
+ }
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
+ if (!warning_issued)
+ WARN(fp->handle, "Discarding range_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warning_issued = 1;
+ continue;
+ }
+ buf[0] = cpu_to_le32(rt->source_type);
+ buf[1] = cpu_to_le32(rt->target_type);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (new_rangetr) {
+ buf[0] = cpu_to_le32(rt->target_class);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ if (mls_write_range_helper(&rt->target_range, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+/************** module writing functions below **************/
+
+static int avrule_write(avrule_t * avrule, struct policy_file *fp)
+{
+ size_t items, items2;
+ uint32_t buf[32], len;
+ class_perm_node_t *cur;
+
+ items = 0;
+ buf[items++] = cpu_to_le32(avrule->specified);
+ buf[items++] = cpu_to_le32(avrule->flags);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&avrule->stypes, fp))
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&avrule->ttypes, fp))
+ return POLICYDB_ERROR;
+
+ cur = avrule->perms;
+ len = 0;
+ while (cur) {
+ len++;
+ cur = cur->next;
+ }
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ cur = avrule->perms;
+ while (cur) {
+ items = 0;
+ buf[items++] = cpu_to_le32(cur->class);
+ buf[items++] = cpu_to_le32(cur->data);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ cur = cur->next;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp)
+{
+ uint32_t buf[32], len;
+ avrule_t *avrule;
+
+ avrule = avrules;
+ len = 0;
+ while (avrule) {
+ len++;
+ avrule = avrule->next;
+ }
+
+ buf[0] = cpu_to_le32(len);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1)
+ return POLICYDB_ERROR;
+
+ avrule = avrules;
+ while (avrule) {
+ avrule_write(avrule, fp);
+ avrule = avrule->next;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int only_process(ebitmap_t *in)
+{
+ unsigned int i;
+ ebitmap_node_t *node;
+
+ ebitmap_for_each_bit(in, node, i) {
+ if (ebitmap_node_get_bit(node, i) &&
+ i != SECCLASS_PROCESS - 1)
+ return 0;
+ }
+ return 1;
+}
+
+static int role_trans_rule_write(policydb_t *p, role_trans_rule_t * t,
+ struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ role_trans_rule_t *tr;
+ int warned = 0;
+ int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS;
+
+ for (tr = t; tr; tr = tr->next)
+ if (new_role || only_process(&tr->classes))
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (tr = t; tr; tr = tr->next) {
+ if (!new_role && !only_process(&tr->classes)) {
+ if (!warned)
+ WARN(fp->handle, "Discarding role_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warned = 1;
+ continue;
+ }
+ if (role_set_write(&tr->roles, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&tr->types, fp))
+ return POLICYDB_ERROR;
+ if (new_role)
+ if (ebitmap_write(&tr->classes, fp))
+ return POLICYDB_ERROR;
+ buf[0] = cpu_to_le32(tr->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ role_allow_rule_t *ra;
+
+ for (ra = r; ra; ra = ra->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ra = r; ra; ra = ra->next) {
+ if (role_set_write(&ra->roles, fp))
+ return POLICYDB_ERROR;
+ if (role_set_write(&ra->new_roles, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[2], len;
+ filename_trans_rule_t *ftr;
+
+ for (ftr = t; ftr; ftr = ftr->next)
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (ftr = t; ftr; ftr = ftr->next) {
+ len = strlen(ftr->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ items = put_entry(ftr->name, sizeof(char), len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&ftr->stypes, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&ftr->ttypes, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(ftr->tclass);
+ buf[1] = cpu_to_le32(ftr->otype);
+
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int range_trans_rule_write(range_trans_rule_t * t,
+ struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ range_trans_rule_t *rt;
+
+ for (rt = t; rt; rt = rt->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (rt = t; rt; rt = rt->next) {
+ if (type_set_write(&rt->stypes, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&rt->ttypes, fp))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&rt->tclasses, fp))
+ return POLICYDB_ERROR;
+ if (mls_write_semantic_range_helper(&rt->trange, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int scope_index_write(scope_index_t * scope_index,
+ unsigned int num_scope_syms,
+ struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1];
+ for (i = 0; i < num_scope_syms; i++) {
+ if (ebitmap_write(scope_index->scope + i, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ buf[0] = cpu_to_le32(scope_index->class_perms_len);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ for (i = 0; i < scope_index->class_perms_len; i++) {
+ if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms,
+ policydb_t * p, struct policy_file *fp)
+{
+ struct policy_data pd;
+ uint32_t buf[2];
+ int i;
+ buf[0] = cpu_to_le32(decl->decl_id);
+ buf[1] = cpu_to_le32(decl->enabled);
+ if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+ return POLICYDB_ERROR;
+ }
+ if (cond_write_list(p, decl->cond_list, fp) == -1 ||
+ avrule_write_list(decl->avrules, fp) == -1 ||
+ role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 ||
+ role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_rule_write(decl->filename_trans_rules, fp))
+ return POLICYDB_ERROR;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+ range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 ||
+ scope_index_write(&decl->declared, num_scope_syms, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ pd.fp = fp;
+ pd.p = p;
+ for (i = 0; i < num_scope_syms; i++) {
+ buf[0] = cpu_to_le32(decl->symtab[i].nprim);
+ buf[1] = cpu_to_le32(decl->symtab[i].table->nel);
+ if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) {
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_block_write(avrule_block_t * block, int num_scope_syms,
+ policydb_t * p, struct policy_file *fp)
+{
+ /* first write a count of the total number of blocks */
+ uint32_t buf[1], num_blocks = 0;
+ avrule_block_t *cur;
+ for (cur = block; cur != NULL; cur = cur->next) {
+ num_blocks++;
+ }
+ buf[0] = cpu_to_le32(num_blocks);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+
+ /* now write each block */
+ for (cur = block; cur != NULL; cur = cur->next) {
+ uint32_t num_decls = 0;
+ avrule_decl_t *decl;
+ /* write a count of number of branches */
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ num_decls++;
+ }
+ buf[0] = cpu_to_le32(num_decls);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (avrule_decl_write(decl, num_scope_syms, p, fp) ==
+ -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ scope_datum_t *scope = (scope_datum_t *) datum;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ uint32_t static_buf[32], *dyn_buf = NULL, *buf;
+ size_t key_len = strlen(key);
+ unsigned int items = 2 + scope->decl_ids_len, i;
+
+ if (items >= (sizeof(static_buf) / 4)) {
+ /* too many things required, so dynamically create a
+ * buffer. this would have been easier with C99's
+ * dynamic arrays... */
+ if ((dyn_buf = malloc(items * sizeof(*dyn_buf))) == NULL) {
+ return POLICYDB_ERROR;
+ }
+ buf = dyn_buf;
+ } else {
+ buf = static_buf;
+ }
+ buf[0] = cpu_to_le32(key_len);
+ if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
+ put_entry(key, 1, key_len, fp) != key_len) {
+ return POLICYDB_ERROR;
+ }
+ buf[0] = cpu_to_le32(scope->scope);
+ buf[1] = cpu_to_le32(scope->decl_ids_len);
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ buf[2 + i] = cpu_to_le32(scope->decl_ids[i]);
+ }
+ if (put_entry(buf, sizeof(*buf), items, fp) != items) {
+ free(dyn_buf);
+ return POLICYDB_ERROR;
+ }
+ free(dyn_buf);
+ return POLICYDB_SUCCESS;
+}
+
+static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
+ hashtab_datum_t datum, void *args)
+{
+ type_datum_t *typdatum = datum;
+ uint32_t *p_nel = args;
+
+ if (typdatum->flavor == TYPE_ATTRIB) {
+ /* uncount attribute from total number of types */
+ (*p_nel)--;
+ }
+ return 0;
+}
+
+/*
+ * Write the configuration data in a policy database
+ * structure to a policy database binary representation
+ * file.
+ */
+int policydb_write(policydb_t * p, struct policy_file *fp)
+{
+ unsigned int i, num_syms;
+ uint32_t buf[32], config;
+ size_t items, items2, len;
+ struct policydb_compat_info *info;
+ struct policy_data pd;
+ char *policydb_str;
+
+ if (p->unsupported_format)
+ return POLICYDB_UNSUPPORTED;
+
+ pd.fp = fp;
+ pd.p = p;
+
+ config = 0;
+ if (p->mls) {
+ if ((p->policyvers < POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_MOD)) {
+ ERR(fp->handle, "policy version %d cannot support MLS",
+ p->policyvers);
+ return POLICYDB_ERROR;
+ }
+ config |= POLICYDB_CONFIG_MLS;
+ }
+
+ config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown);
+
+ /* Write the magic number and string identifiers. */
+ items = 0;
+ if (p->policy_type == POLICY_KERN) {
+ buf[items++] = cpu_to_le32(POLICYDB_MAGIC);
+ len = strlen(policydb_target_strings[p->target_platform]);
+ policydb_str = policydb_target_strings[p->target_platform];
+ } else {
+ buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC);
+ len = strlen(POLICYDB_MOD_STRING);
+ policydb_str = POLICYDB_MOD_STRING;
+ }
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ items = put_entry(policydb_str, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ /* Write the version, config, and table sizes. */
+ items = 0;
+ info = policydb_lookup_compat(p->policyvers, p->policy_type,
+ p->target_platform);
+ if (!info) {
+ ERR(fp->handle, "compatibility lookup failed for policy "
+ "version %d", p->policyvers);
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type != POLICY_KERN) {
+ buf[items++] = cpu_to_le32(p->policy_type);
+ }
+ buf[items++] = cpu_to_le32(p->policyvers);
+ buf[items++] = cpu_to_le32(config);
+ buf[items++] = cpu_to_le32(info->sym_num);
+ buf[items++] = cpu_to_le32(info->ocon_num);
+
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type == POLICY_MOD) {
+ /* Write module name and version */
+ len = strlen(p->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(p->name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ len = strlen(p->version);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(p->version, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_MOD)) {
+ if (ebitmap_write(&p->policycaps, fp) == -1)
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policyvers < POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ ebitmap_node_t *tnode;
+
+ ebitmap_for_each_bit(&p->permissive_map, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ WARN(fp->handle, "Warning! Policy version %d cannot "
+ "support permissive types, but some were defined",
+ p->policyvers);
+ break;
+ }
+ }
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&p->permissive_map, fp) == -1)
+ return POLICYDB_ERROR;
+ }
+
+ num_syms = info->sym_num;
+ for (i = 0; i < num_syms; i++) {
+ buf[0] = cpu_to_le32(p->symtab[i].nprim);
+ buf[1] = cpu_to_le32(p->symtab[i].table->nel);
+
+ /*
+ * A special case when writing type/attribute symbol table.
+ * The kernel policy version less than 24 does not support
+ * to load entries of attribute, so we have to re-calculate
+ * the actual number of types except for attributes.
+ */
+ if (i == SYM_TYPES &&
+ p->policyvers < POLICYDB_VERSION_BOUNDARY &&
+ p->policy_type == POLICY_KERN) {
+ hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]);
+ }
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (hashtab_map(p->symtab[i].table, write_f[i], &pd))
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (avtab_write(p, &p->te_avtab, fp))
+ return POLICYDB_ERROR;
+ if (p->policyvers < POLICYDB_VERSION_BOOL) {
+ if (p->p_bools.nprim)
+ WARN(fp->handle, "Discarding "
+ "booleans and conditional rules");
+ } else {
+ if (cond_write_list(p, p->cond_list, fp))
+ return POLICYDB_ERROR;
+ }
+ if (role_trans_write(p, fp))
+ return POLICYDB_ERROR;
+ if (role_allow_write(p->role_allow, fp))
+ return POLICYDB_ERROR;
+ if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
+ if (filename_trans_write(p->filename_trans, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (p->filename_trans)
+ WARN(fp->handle, "Discarding filename type transition rules");
+ }
+ } else {
+ if (avrule_block_write(p->global, num_syms, p, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ for (i = 0; i < num_syms; i++) {
+ buf[0] = cpu_to_le32(p->scope[i].table->nel);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(p->scope[i].table, scope_write, &pd))
+ return POLICYDB_ERROR;
+ }
+ }
+
+ if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS
+ && p->policy_type == POLICY_BASE)) {
+ if (range_write(p, fp)) {
+ return POLICYDB_ERROR;
+ }
+ }
+
+ if (p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_AVTAB) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_write(&p->type_attr_map[i], fp) == -1)
+ return POLICYDB_ERROR;
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..dd7bd33
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,54 @@
+M4 ?= m4
+MKDIR ?= mkdir
+EXE ?= libsepol-tests
+
+CFLAGS += -g3 -gdwarf-2 -o0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter -Werror
+
+# Statically link libsepol on the assumption that we are going to
+# be testing internal functions.
+LIBSEPOL := ../src/libsepol.a
+
+# In order to load source policies we need to link in the checkpolicy/checkmodule parser and util code.
+# This is less than ideal, but it makes the tests easier to maintain by allowing source policies
+# to be loaded directly.
+CHECKPOLICY := ../../checkpolicy/
+CPPFLAGS += -I../include/ -I$(CHECKPOLICY)
+
+# test program object files
+objs := $(patsubst %.c,%.o,$(wildcard *.c))
+parserobjs := $(CHECKPOLICY)queue.o $(CHECKPOLICY)y.tab.o \
+ $(CHECKPOLICY)parse_util.o $(CHECKPOLICY)lex.yy.o \
+ $(CHECKPOLICY)policy_define.o $(CHECKPOLICY)module_compiler.o
+
+# test policy pieces
+m4support := $(wildcard policies/support/*.spt)
+testsuites := $(wildcard policies/test-*)
+policysrc := $(foreach path,$(testsuites),$(wildcard $(path)/*.conf))
+stdpol := $(addsuffix .std,$(policysrc))
+mlspol := $(addsuffix .mls,$(policysrc))
+policies := $(stdpol) $(mlspol)
+
+all: $(EXE) $(policies)
+policies: $(policies)
+
+$(EXE): $(objs) $(parserobjs) $(LIBSEPOL)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(objs) $(parserobjs) -lfl -lcunit -lcurses $(LIBSEPOL) -o $@
+
+%.conf.std: $(m4support) %.conf
+ $(M4) $(M4PARAMS) $^ > $@
+
+%.conf.mls: $(m4support) %.conf
+ $(M4) $(M4PARAMS) -D enable_mls $^ > $@
+
+clean:
+ rm -f $(objs) $(EXE)
+ rm -f $(policies)
+ rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo
+
+
+test: $(EXE) $(policies)
+ $(MKDIR) -p policies/test-downgrade
+ ../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi
+ ./$(EXE)
+
+.PHONY: all policies clean test
diff --git a/tests/debug.c b/tests/debug.c
new file mode 100644
index 0000000..90aa6e0
--- /dev/null
+++ b/tests/debug.c
@@ -0,0 +1,69 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include "debug.h"
+
+#include <stdlib.h>
+
+void print_ebitmap(ebitmap_t * bitmap, FILE * fp)
+{
+ uint32_t i;
+ for (i = 0; i < bitmap->highbit; i++) {
+ fprintf(fp, "%d", ebitmap_get_bit(bitmap, i));
+ }
+ fprintf(fp, "\n");
+}
+
+/* stolen from dispol.c */
+void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
+{
+
+ cond_expr_t *cur;
+ for (cur = exp; cur != NULL; cur = cur->next) {
+ switch (cur->expr_type) {
+ case COND_BOOL:
+ fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]);
+ break;
+ case COND_NOT:
+ fprintf(fp, "! ");
+ break;
+ case COND_OR:
+ fprintf(fp, "|| ");
+ break;
+ case COND_AND:
+ fprintf(fp, "&& ");
+ break;
+ case COND_XOR:
+ fprintf(fp, "^ ");
+ break;
+ case COND_EQ:
+ fprintf(fp, "== ");
+ break;
+ case COND_NEQ:
+ fprintf(fp, "!= ");
+ break;
+ default:
+ fprintf(fp, "error! (%d)", cur->expr_type);
+ break;
+ }
+ }
+}
diff --git a/tests/debug.h b/tests/debug.h
new file mode 100644
index 0000000..c25ebd4
--- /dev/null
+++ b/tests/debug.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+extern void print_ebitmap(ebitmap_t * bitmap, FILE * fp);
+extern void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp);
diff --git a/tests/helpers.c b/tests/helpers.c
new file mode 100644
index 0000000..542e467
--- /dev/null
+++ b/tests/helpers.c
@@ -0,0 +1,81 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This has helper functions that are common between tests */
+
+#include "helpers.h"
+#include "parse_util.h"
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+#include <stdlib.h>
+#include <limits.h>
+
+int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name)
+{
+ char filename[PATH_MAX];
+
+ if (mls) {
+ if (snprintf(filename, PATH_MAX, "policies/%s/%s.mls", test_name, policy_name) < 0) {
+ return -1;
+ }
+ } else {
+ if (snprintf(filename, PATH_MAX, "policies/%s/%s.std", test_name, policy_name) < 0) {
+ return -1;
+ }
+ }
+
+ if (policydb_init(p)) {
+ fprintf(stderr, "Out of memory");
+ return -1;
+ }
+
+ p->policy_type = policy_type;
+ p->mls = mls;
+
+ if (read_source_policy(p, filename, test_name)) {
+ fprintf(stderr, "failed to read policy %s\n", filename);
+ policydb_destroy(p);
+ return -1;
+ }
+
+ return 0;
+}
+
+avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym)
+{
+ scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symtab].table, sym);
+
+ if (scope == NULL) {
+ return NULL;
+ }
+ if (scope->scope != SCOPE_DECL) {
+ return NULL;
+ }
+ if (scope->decl_ids_len != 1) {
+ return NULL;
+ }
+
+ return p->decl_val_to_struct[scope->decl_ids[0] - 1];
+}
diff --git a/tests/helpers.h b/tests/helpers.h
new file mode 100644
index 0000000..418ee95
--- /dev/null
+++ b/tests/helpers.h
@@ -0,0 +1,59 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+/* helper functions */
+
+/* Load a source policy into p. policydb_init will called within this function.
+ *
+ * Example: test_load_policy(p, POLICY_BASE, 1, "foo", "base.conf") will load the
+ * policy "policies/foo/mls/base.conf" into p.
+ *
+ * Arguments:
+ * p policydb_t into which the policy will be read. This should be
+ * malloc'd but not passed to policydb_init.
+ * policy_type Type of policy expected - POLICY_BASE or POLICY_MOD.
+ * mls Boolean value indicating whether an mls policy is expected.
+ * test_name Name of the test which will be the name of the directory in
+ * which the policies are stored.
+ * policy_name Name of the policy in the directory.
+ *
+ * Returns:
+ * 0 success
+ * -1 error - the policydb will be destroyed but not freed.
+ */
+extern int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name);
+
+/* Find an avrule_decl_t by a unique symbol. If the symbol is declared in more
+ * than one decl an error is returned.
+ *
+ * Returns:
+ * decl success
+ * NULL error (including more than one declaration)
+ */
+extern avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym);
+
+#endif
diff --git a/tests/libsepol-tests.c b/tests/libsepol-tests.c
new file mode 100644
index 0000000..9302f72
--- /dev/null
+++ b/tests/libsepol-tests.c
@@ -0,0 +1,118 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-cond.h"
+#include "test-linker.h"
+#include "test-expander.h"
+#include "test-deps.h"
+#include "test-downgrade.h"
+
+#include <CUnit/Basic.h>
+#include <CUnit/Console.h>
+#include <CUnit/TestDB.h>
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+int mls;
+
+#define DECLARE_SUITE(name) \
+ suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \
+ if (NULL == suite) { \
+ CU_cleanup_registry(); \
+ return CU_get_error(); } \
+ if (name##_add_tests(suite)) { \
+ CU_cleanup_registry(); \
+ return CU_get_error(); }
+
+static void usage(char *progname)
+{
+ printf("usage: %s [options]\n", progname);
+ printf("options:\n");
+ printf("\t-v, --verbose\t\t\tverbose output\n");
+ printf("\t-i, --interactive\t\tinteractive console\n");
+}
+
+static int do_tests(int interactive, int verbose)
+{
+ CU_pSuite suite = NULL;
+
+ if (CUE_SUCCESS != CU_initialize_registry())
+ return CU_get_error();
+
+ DECLARE_SUITE(cond);
+ DECLARE_SUITE(linker);
+ DECLARE_SUITE(expander);
+ DECLARE_SUITE(deps);
+ DECLARE_SUITE(downgrade);
+
+ if (verbose)
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ else
+ CU_basic_set_mode(CU_BRM_NORMAL);
+
+ if (interactive)
+ CU_console_run_tests();
+ else
+ CU_basic_run_tests();
+ CU_cleanup_registry();
+ return CU_get_error();
+
+}
+
+int main(int argc, char **argv)
+{
+ int i, verbose = 1, interactive = 0;
+
+ struct option opts[] = {
+ {"verbose", 0, NULL, 'v'},
+ {"interactive", 0, NULL, 'i'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while ((i = getopt_long(argc, argv, "vi", opts, NULL)) != -1) {
+ switch (i) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'h':
+ default:{
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ }
+
+ /* first do the non-mls tests */
+ mls = 0;
+ if (do_tests(interactive, verbose))
+ return -1;
+
+ /* then with mls */
+ mls = 1;
+ if (do_tests(interactive, verbose))
+ return -1;
+
+ return 0;
+}
diff --git a/tests/policies/support/misc_macros.spt b/tests/policies/support/misc_macros.spt
new file mode 100644
index 0000000..5fadd0f
--- /dev/null
+++ b/tests/policies/support/misc_macros.spt
@@ -0,0 +1,23 @@
+
+########################################
+#
+# Helper macros
+#
+
+########################################
+#
+# gen_user(username, prefix, role_set, mls_defaultlevel, mls_range, [mcs_categories])
+#
+define(`gen_user',`dnl
+ifdef(`users_extra',`dnl
+ifelse(`$2',,,`user $1 prefix $2;')
+',`dnl
+user $1 roles { $3 }`'ifdef(`enable_mls', ` level $4 range $5')`'ifdef(`enable_mcs',` level s0 range s0`'ifelse(`$6',,,` - s0:$6')');
+')dnl
+')
+
+########################################
+#
+# gen_context(context,mls_sensitivity,[mcs_categories])
+#
+define(`gen_context',`$1`'ifdef(`enable_mls',`:$2')`'ifdef(`enable_mcs',`:s0`'ifelse(`$3',,,`:$3')')') dnl
diff --git a/tests/policies/test-cond/refpolicy-base.conf b/tests/policies/test-cond/refpolicy-base.conf
new file mode 100644
index 0000000..60da11a
--- /dev/null
+++ b/tests/policies/test-cond/refpolicy-base.conf
@@ -0,0 +1,1939 @@
+class security
+class process
+class system
+class capability
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+class sem
+class msg
+class msgq
+class shm
+class ipc
+class passwd # userspace
+class drawable # userspace
+class window # userspace
+class gc # userspace
+class font # userspace
+class colormap # userspace
+class property # userspace
+class cursor # userspace
+class xclient # userspace
+class xinput # userspace
+class xserver # userspace
+class xextension # userspace
+class pax
+class netlink_route_socket
+class netlink_firewall_socket
+class netlink_tcpdiag_socket
+class netlink_nflog_socket
+class netlink_xfrm_socket
+class netlink_selinux_socket
+class netlink_audit_socket
+class netlink_ip6fw_socket
+class netlink_dnrt_socket
+class dbus # userspace
+class nscd # userspace
+class association
+class netlink_kobject_uevent_socket
+sid kernel
+sid security
+sid unlabeled
+sid fs
+sid file
+sid file_labels
+sid init
+sid any_socket
+sid port
+sid netif
+sid netmsg
+sid node
+sid igmp_packet
+sid icmp_socket
+sid tcp_socket
+sid sysctl_modprobe
+sid sysctl
+sid sysctl_fs
+sid sysctl_kernel
+sid sysctl_net
+sid sysctl_net_unix
+sid sysctl_vm
+sid sysctl_dev
+sid kmod
+sid policy
+sid scmp_packet
+sid devnull
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+common socket
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+ execmod
+}
+class lnk_file
+inherits file
+class chr_file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+ execmod
+}
+class blk_file
+inherits file
+class sock_file
+inherits file
+class fifo_file
+inherits file
+class fd
+{
+ use
+}
+class socket
+inherits socket
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+ node_bind
+ name_connect
+}
+class udp_socket
+inherits socket
+{
+ node_bind
+}
+class rawip_socket
+inherits socket
+{
+ node_bind
+}
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+class netlink_socket
+inherits socket
+class packet_socket
+inherits socket
+class key_socket
+inherits socket
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+class unix_dgram_socket
+inherits socket
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+ getattr
+ setexec
+ setfscreate
+ noatsecure
+ siginh
+ setrlimit
+ rlimitinh
+ dyntransition
+ setcurrent
+ execmem
+ execstack
+ execheap
+}
+class ipc
+inherits ipc
+class sem
+inherits ipc
+class msgq
+inherits ipc
+{
+ enqueue
+}
+class msg
+{
+ send
+ receive
+}
+class shm
+inherits ipc
+{
+ lock
+}
+class security
+{
+ compute_av
+ compute_create
+ compute_member
+ check_context
+ load_policy
+ compute_relabel
+ compute_user
+ setenforce # was avc_toggle in system class
+ setbool
+ setsecparam
+ setcheckreqprot
+}
+class system
+{
+ ipc_info
+ syslog_read
+ syslog_mod
+ syslog_console
+}
+class capability
+{
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+ audit_write
+ audit_control
+}
+class passwd
+{
+ passwd # change another user passwd
+ chfn # change another user finger info
+ chsh # change another user shell
+ rootok # pam_rootok check (skip auth)
+ crontab # crontab on another user
+}
+class drawable
+{
+ create
+ destroy
+ draw
+ copy
+ getattr
+}
+class gc
+{
+ create
+ free
+ getattr
+ setattr
+}
+class window
+{
+ addchild
+ create
+ destroy
+ map
+ unmap
+ chstack
+ chproplist
+ chprop
+ listprop
+ getattr
+ setattr
+ setfocus
+ move
+ chselection
+ chparent
+ ctrllife
+ enumerate
+ transparent
+ mousemotion
+ clientcomevent
+ inputevent
+ drawevent
+ windowchangeevent
+ windowchangerequest
+ serverchangeevent
+ extensionevent
+}
+class font
+{
+ load
+ free
+ getattr
+ use
+}
+class colormap
+{
+ create
+ free
+ install
+ uninstall
+ list
+ read
+ store
+ getattr
+ setattr
+}
+class property
+{
+ create
+ free
+ read
+ write
+}
+class cursor
+{
+ create
+ createglyph
+ free
+ assign
+ setattr
+}
+class xclient
+{
+ kill
+}
+class xinput
+{
+ lookup
+ getattr
+ setattr
+ setfocus
+ warppointer
+ activegrab
+ passivegrab
+ ungrab
+ bell
+ mousemotion
+ relabelinput
+}
+class xserver
+{
+ screensaver
+ gethostlist
+ sethostlist
+ getfontpath
+ setfontpath
+ getattr
+ grab
+ ungrab
+}
+class xextension
+{
+ query
+ use
+}
+class pax
+{
+ pageexec # Paging based non-executable pages
+ emutramp # Emulate trampolines
+ mprotect # Restrict mprotect()
+ randmmap # Randomize mmap() base
+ randexec # Randomize ET_EXEC base
+ segmexec # Segmentation based non-executable pages
+}
+class netlink_route_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_firewall_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_tcpdiag_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_nflog_socket
+inherits socket
+class netlink_xfrm_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_selinux_socket
+inherits socket
+class netlink_audit_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+ nlmsg_relay
+ nlmsg_readpriv
+}
+class netlink_ip6fw_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_dnrt_socket
+inherits socket
+class dbus
+{
+ acquire_svc
+ send_msg
+}
+class nscd
+{
+ getpwd
+ getgrp
+ gethost
+ getstat
+ admin
+ shmempwd
+ shmemgrp
+ shmemhost
+}
+class association
+{
+ sendto
+ recvfrom
+ setcontext
+}
+class netlink_kobject_uevent_socket
+inherits socket
+sensitivity s0;
+dominance { s0 }
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+category c24; category c25; category c26; category c27;
+category c28; category c29; category c30; category c31;
+category c32; category c33; category c34; category c35;
+category c36; category c37; category c38; category c39;
+category c40; category c41; category c42; category c43;
+category c44; category c45; category c46; category c47;
+category c48; category c49; category c50; category c51;
+category c52; category c53; category c54; category c55;
+category c56; category c57; category c58; category c59;
+category c60; category c61; category c62; category c63;
+category c64; category c65; category c66; category c67;
+category c68; category c69; category c70; category c71;
+category c72; category c73; category c74; category c75;
+category c76; category c77; category c78; category c79;
+category c80; category c81; category c82; category c83;
+category c84; category c85; category c86; category c87;
+category c88; category c89; category c90; category c91;
+category c92; category c93; category c94; category c95;
+category c96; category c97; category c98; category c99;
+category c100; category c101; category c102; category c103;
+category c104; category c105; category c106; category c107;
+category c108; category c109; category c110; category c111;
+category c112; category c113; category c114; category c115;
+category c116; category c117; category c118; category c119;
+category c120; category c121; category c122; category c123;
+category c124; category c125; category c126; category c127;
+category c128; category c129; category c130; category c131;
+category c132; category c133; category c134; category c135;
+category c136; category c137; category c138; category c139;
+category c140; category c141; category c142; category c143;
+category c144; category c145; category c146; category c147;
+category c148; category c149; category c150; category c151;
+category c152; category c153; category c154; category c155;
+category c156; category c157; category c158; category c159;
+category c160; category c161; category c162; category c163;
+category c164; category c165; category c166; category c167;
+category c168; category c169; category c170; category c171;
+category c172; category c173; category c174; category c175;
+category c176; category c177; category c178; category c179;
+category c180; category c181; category c182; category c183;
+category c184; category c185; category c186; category c187;
+category c188; category c189; category c190; category c191;
+category c192; category c193; category c194; category c195;
+category c196; category c197; category c198; category c199;
+category c200; category c201; category c202; category c203;
+category c204; category c205; category c206; category c207;
+category c208; category c209; category c210; category c211;
+category c212; category c213; category c214; category c215;
+category c216; category c217; category c218; category c219;
+category c220; category c221; category c222; category c223;
+category c224; category c225; category c226; category c227;
+category c228; category c229; category c230; category c231;
+category c232; category c233; category c234; category c235;
+category c236; category c237; category c238; category c239;
+category c240; category c241; category c242; category c243;
+category c244; category c245; category c246; category c247;
+category c248; category c249; category c250; category c251;
+category c252; category c253; category c254; category c255;
+level s0:c0.c255;
+mlsconstrain file { write setattr append unlink link rename
+ ioctl lock execute relabelfrom } (h1 dom h2);
+mlsconstrain file { create relabelto } ((h1 dom h2) and (l2 eq h2));
+mlsconstrain file { read } ((h1 dom h2) or ( t2 == domain ) or ( t1 == mlsfileread ));
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { relabelfrom }
+ ( h1 dom h2 );
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { create relabelto }
+ (( h1 dom h2 ) and ( l2 eq h2 ));
+mlsconstrain process { ptrace } ( h1 dom h2 );
+mlsconstrain process { sigkill sigstop } ( h1 dom h2 ) or
+ ( t1 == mcskillall );
+mlsconstrain xextension query ( t1 == mlsfileread );
+attribute netif_type;
+attribute node_type;
+attribute port_type;
+attribute reserved_port_type;
+attribute device_node;
+attribute memory_raw_read;
+attribute memory_raw_write;
+attribute domain;
+attribute unconfined_domain_type;
+attribute set_curr_context;
+attribute entry_type;
+attribute privfd;
+attribute can_change_process_identity;
+attribute can_change_process_role;
+attribute can_change_object_identity;
+attribute can_system_change;
+attribute process_user_target;
+attribute cron_source_domain;
+attribute cron_job_domain;
+attribute process_uncond_exempt; # add userhelperdomain to this one
+attribute file_type;
+attribute lockfile;
+attribute mountpoint;
+attribute pidfile;
+attribute polydir;
+attribute usercanread;
+attribute polyparent;
+attribute polymember;
+attribute security_file_type;
+attribute tmpfile;
+attribute tmpfsfile;
+attribute filesystem_type;
+attribute noxattrfs;
+attribute can_load_kernmodule;
+attribute can_receive_kernel_messages;
+attribute kern_unconfined;
+attribute proc_type;
+attribute sysctl_type;
+attribute mcskillall;
+attribute mlsfileread;
+attribute mlsfilereadtoclr;
+attribute mlsfilewrite;
+attribute mlsfilewritetoclr;
+attribute mlsfileupgrade;
+attribute mlsfiledowngrade;
+attribute mlsnetread;
+attribute mlsnetreadtoclr;
+attribute mlsnetwrite;
+attribute mlsnetwritetoclr;
+attribute mlsnetupgrade;
+attribute mlsnetdowngrade;
+attribute mlsnetrecvall;
+attribute mlsipcread;
+attribute mlsipcreadtoclr;
+attribute mlsipcwrite;
+attribute mlsipcwritetoclr;
+attribute mlsprocread;
+attribute mlsprocreadtoclr;
+attribute mlsprocwrite;
+attribute mlsprocwritetoclr;
+attribute mlsprocsetsl;
+attribute mlsxwinread;
+attribute mlsxwinreadtoclr;
+attribute mlsxwinwrite;
+attribute mlsxwinwritetoclr;
+attribute mlsxwinreadproperty;
+attribute mlsxwinwriteproperty;
+attribute mlsxwinreadcolormap;
+attribute mlsxwinwritecolormap;
+attribute mlsxwinwritexinput;
+attribute mlstrustedobject;
+attribute privrangetrans;
+attribute mlsrangetrans;
+attribute can_load_policy;
+attribute can_setenforce;
+attribute can_setsecparam;
+attribute ttynode;
+attribute ptynode;
+attribute server_ptynode;
+attribute serial_device;
+type bin_t;
+type sbin_t;
+type ls_exec_t;
+type shell_exec_t;
+type chroot_exec_t;
+type ppp_device_t;
+type tun_tap_device_t;
+type port_t, port_type;
+type reserved_port_t, port_type, reserved_port_type;
+type afs_bos_port_t, port_type;
+type afs_fs_port_t, port_type;
+type afs_ka_port_t, port_type;
+type afs_pt_port_t, port_type;
+type afs_vl_port_t, port_type;
+type amanda_port_t, port_type;
+type amavisd_recv_port_t, port_type;
+type amavisd_send_port_t, port_type;
+type asterisk_port_t, port_type;
+type auth_port_t, port_type;
+type bgp_port_t, port_type;
+type biff_port_t, port_type, reserved_port_type;
+type clamd_port_t, port_type;
+type clockspeed_port_t, port_type;
+type comsat_port_t, port_type;
+type cvs_port_t, port_type;
+type dcc_port_t, port_type;
+type dbskkd_port_t, port_type;
+type dhcpc_port_t, port_type;
+type dhcpd_port_t, port_type;
+type dict_port_t, port_type;
+type distccd_port_t, port_type;
+type dns_port_t, port_type;
+type fingerd_port_t, port_type;
+type ftp_data_port_t, port_type;
+type ftp_port_t, port_type;
+type gatekeeper_port_t, port_type;
+type giftd_port_t, port_type;
+type gopher_port_t, port_type;
+type http_cache_port_t, port_type;
+type http_port_t, port_type;
+type howl_port_t, port_type;
+type hplip_port_t, port_type;
+type i18n_input_port_t, port_type;
+type imaze_port_t, port_type;
+type inetd_child_port_t, port_type;
+type innd_port_t, port_type;
+type ipp_port_t, port_type;
+type ircd_port_t, port_type;
+type isakmp_port_t, port_type;
+type jabber_client_port_t, port_type;
+type jabber_interserver_port_t, port_type;
+type kerberos_admin_port_t, port_type;
+type kerberos_master_port_t, port_type;
+type kerberos_port_t, port_type;
+type ktalkd_port_t, port_type;
+type ldap_port_t, port_type;
+type lrrd_port_t, port_type;
+type mail_port_t, port_type;
+type monopd_port_t, port_type;
+type mysqld_port_t, port_type;
+type nessus_port_t, port_type;
+type nmbd_port_t, port_type;
+type ntp_port_t, port_type;
+type openvpn_port_t, port_type;
+type pegasus_http_port_t, port_type;
+type pegasus_https_port_t, port_type;
+type pop_port_t, port_type;
+type portmap_port_t, port_type;
+type postgresql_port_t, port_type;
+type postgrey_port_t, port_type;
+type printer_port_t, port_type;
+type ptal_port_t, port_type;
+type pxe_port_t, port_type;
+type pyzor_port_t, port_type;
+type radacct_port_t, port_type;
+type radius_port_t, port_type;
+type razor_port_t, port_type;
+type rlogind_port_t, port_type;
+type rndc_port_t, port_type;
+type router_port_t, port_type;
+type rsh_port_t, port_type;
+type rsync_port_t, port_type;
+type smbd_port_t, port_type;
+type smtp_port_t, port_type;
+type snmp_port_t, port_type;
+type spamd_port_t, port_type;
+type ssh_port_t, port_type;
+type soundd_port_t, port_type;
+type socks_port_t, port_type; type stunnel_port_t, port_type;
+type swat_port_t, port_type;
+type syslogd_port_t, port_type;
+type telnetd_port_t, port_type;
+type tftp_port_t, port_type;
+type transproxy_port_t, port_type;
+type utcpserver_port_t, port_type;
+type uucpd_port_t, port_type;
+type vnc_port_t, port_type;
+type xserver_port_t, port_type;
+type xen_port_t, port_type;
+type zebra_port_t, port_type;
+type zope_port_t, port_type;
+type node_t, node_type;
+type compat_ipv4_node_t alias node_compat_ipv4_t, node_type;
+type inaddr_any_node_t alias node_inaddr_any_t, node_type;
+type node_internal_t, node_type;
+type link_local_node_t alias node_link_local_t, node_type;
+type lo_node_t alias node_lo_t, node_type;
+type mapped_ipv4_node_t alias node_mapped_ipv4_t, node_type;
+type multicast_node_t alias node_multicast_t, node_type;
+type site_local_node_t alias node_site_local_t, node_type;
+type unspec_node_t alias node_unspec_t, node_type;
+type netif_t, netif_type;
+type device_t;
+type agp_device_t;
+type apm_bios_t;
+type cardmgr_dev_t;
+type clock_device_t;
+type cpu_device_t;
+type crypt_device_t;
+type dri_device_t;
+type event_device_t;
+type framebuf_device_t;
+type lvm_control_t;
+type memory_device_t;
+type misc_device_t;
+type mouse_device_t;
+type mtrr_device_t;
+type null_device_t;
+type power_device_t;
+type printer_device_t;
+type random_device_t;
+type scanner_device_t;
+type sound_device_t;
+type sysfs_t;
+type urandom_device_t;
+type usbfs_t alias usbdevfs_t;
+type usb_device_t;
+type v4l_device_t;
+type xserver_misc_device_t;
+type zero_device_t;
+type xconsole_device_t;
+type devfs_control_t;
+type boot_t;
+type default_t, file_type, mountpoint;
+type etc_t, file_type;
+type etc_runtime_t, file_type;
+type file_t, file_type, mountpoint;
+type home_root_t, file_type, mountpoint;
+type lost_found_t, file_type;
+type mnt_t, file_type, mountpoint;
+type modules_object_t;
+type no_access_t, file_type;
+type poly_t, file_type;
+type readable_t, file_type;
+type root_t, file_type, mountpoint;
+type src_t, file_type, mountpoint;
+type system_map_t;
+type tmp_t, mountpoint; #, polydir
+type usr_t, file_type, mountpoint;
+type var_t, file_type, mountpoint;
+type var_lib_t, file_type, mountpoint;
+type var_lock_t, file_type, lockfile;
+type var_run_t, file_type, pidfile;
+type var_spool_t;
+type fs_t;
+type bdev_t;
+type binfmt_misc_fs_t;
+type capifs_t;
+type configfs_t;
+type eventpollfs_t;
+type futexfs_t;
+type hugetlbfs_t;
+type inotifyfs_t;
+type nfsd_fs_t;
+type ramfs_t;
+type romfs_t;
+type rpc_pipefs_t;
+type tmpfs_t;
+type autofs_t, noxattrfs;
+type cifs_t alias sambafs_t, noxattrfs;
+type dosfs_t, noxattrfs;
+type iso9660_t, filesystem_type, noxattrfs;
+type removable_t, noxattrfs;
+type nfs_t, filesystem_type, noxattrfs;
+type kernel_t, can_load_kernmodule;
+type debugfs_t;
+type proc_t, proc_type;
+type proc_kmsg_t, proc_type;
+type proc_kcore_t, proc_type;
+type proc_mdstat_t, proc_type;
+type proc_net_t, proc_type;
+type proc_xen_t, proc_type;
+type sysctl_t, sysctl_type;
+type sysctl_irq_t, sysctl_type;
+type sysctl_rpc_t, sysctl_type;
+type sysctl_fs_t, sysctl_type;
+type sysctl_kernel_t, sysctl_type;
+type sysctl_modprobe_t, sysctl_type;
+type sysctl_hotplug_t, sysctl_type;
+type sysctl_net_t, sysctl_type;
+type sysctl_net_unix_t, sysctl_type;
+type sysctl_vm_t, sysctl_type;
+type sysctl_dev_t, sysctl_type;
+type unlabeled_t;
+type auditd_exec_t;
+type crond_exec_t;
+type cupsd_exec_t;
+type getty_t;
+type init_t;
+type init_exec_t;
+type initrc_t;
+type initrc_exec_t;
+type login_exec_t;
+type sshd_exec_t;
+type su_exec_t;
+type udev_exec_t;
+type unconfined_t;
+type xdm_exec_t;
+type lvm_exec_t;
+type security_t;
+type bsdpty_device_t;
+type console_device_t;
+type devpts_t;
+type devtty_t;
+type ptmx_t;
+type tty_device_t, serial_device;
+type usbtty_device_t, serial_device;
+ bool secure_mode false;
+ bool secure_mode_insmod false;
+ bool secure_mode_policyload false;
+ bool allow_cvs_read_shadow false;
+ bool allow_execheap false;
+ bool allow_execmem true;
+ bool allow_execmod false;
+ bool allow_execstack true;
+ bool allow_ftpd_anon_write false;
+ bool allow_gssd_read_tmp true;
+ bool allow_httpd_anon_write false;
+ bool allow_java_execstack false;
+ bool allow_kerberos true;
+ bool allow_rsync_anon_write false;
+ bool allow_saslauthd_read_shadow false;
+ bool allow_smbd_anon_write false;
+ bool allow_ptrace false;
+ bool allow_ypbind false;
+ bool fcron_crond false;
+ bool ftp_home_dir false;
+ bool ftpd_is_daemon true;
+ bool httpd_builtin_scripting true;
+ bool httpd_can_network_connect false;
+ bool httpd_can_network_connect_db false;
+ bool httpd_can_network_relay false;
+ bool httpd_enable_cgi true;
+ bool httpd_enable_ftp_server false;
+ bool httpd_enable_homedirs true;
+ bool httpd_ssi_exec true;
+ bool httpd_tty_comm false;
+ bool httpd_unified true;
+ bool named_write_master_zones false;
+ bool nfs_export_all_rw true;
+ bool nfs_export_all_ro true;
+ bool pppd_can_insmod false;
+ bool read_default_t true;
+ bool run_ssh_inetd false;
+ bool samba_enable_home_dirs false;
+ bool spamassasin_can_network false;
+ bool squid_connect_any false;
+ bool ssh_sysadm_login false;
+ bool stunnel_is_daemon false;
+ bool use_nfs_home_dirs false;
+ bool use_samba_home_dirs false;
+ bool user_ping true;
+ bool spamd_enable_home_dirs true;
+ allow bin_t fs_t:filesystem associate;
+ allow bin_t noxattrfs:filesystem associate;
+ typeattribute bin_t file_type;
+ allow sbin_t fs_t:filesystem associate;
+ allow sbin_t noxattrfs:filesystem associate;
+ typeattribute sbin_t file_type;
+ allow ls_exec_t fs_t:filesystem associate;
+ allow ls_exec_t noxattrfs:filesystem associate;
+ typeattribute ls_exec_t file_type;
+typeattribute ls_exec_t entry_type;
+ allow shell_exec_t fs_t:filesystem associate;
+ allow shell_exec_t noxattrfs:filesystem associate;
+ typeattribute shell_exec_t file_type;
+ allow chroot_exec_t fs_t:filesystem associate;
+ allow chroot_exec_t noxattrfs:filesystem associate;
+ typeattribute chroot_exec_t file_type;
+ typeattribute ppp_device_t device_node;
+ allow ppp_device_t fs_t:filesystem associate;
+ allow ppp_device_t tmpfs_t:filesystem associate;
+ allow ppp_device_t tmp_t:filesystem associate;
+ typeattribute tun_tap_device_t device_node;
+ allow tun_tap_device_t fs_t:filesystem associate;
+ allow tun_tap_device_t tmpfs_t:filesystem associate;
+ allow tun_tap_device_t tmp_t:filesystem associate;
+typeattribute auth_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute comsat_port_t reserved_port_type;
+typeattribute dhcpc_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute fingerd_port_t reserved_port_type;
+typeattribute ftp_data_port_t reserved_port_type;
+typeattribute ftp_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute innd_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute isakmp_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute ntp_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute printer_port_t reserved_port_type;
+typeattribute rlogind_port_t reserved_port_type;
+typeattribute rndc_port_t reserved_port_type;
+typeattribute router_port_t reserved_port_type;
+typeattribute rsh_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute spamd_port_t reserved_port_type;
+typeattribute ssh_port_t reserved_port_type;
+typeattribute swat_port_t reserved_port_type;
+typeattribute syslogd_port_t reserved_port_type;
+typeattribute telnetd_port_t reserved_port_type;
+typeattribute tftp_port_t reserved_port_type;
+typeattribute uucpd_port_t reserved_port_type;
+ allow device_t tmpfs_t:filesystem associate;
+ allow device_t fs_t:filesystem associate;
+ allow device_t noxattrfs:filesystem associate;
+ typeattribute device_t file_type;
+ allow device_t fs_t:filesystem associate;
+ allow device_t noxattrfs:filesystem associate;
+ typeattribute device_t file_type;
+ typeattribute device_t mountpoint;
+ allow device_t tmp_t:filesystem associate;
+ typeattribute agp_device_t device_node;
+ allow agp_device_t fs_t:filesystem associate;
+ allow agp_device_t tmpfs_t:filesystem associate;
+ allow agp_device_t tmp_t:filesystem associate;
+ typeattribute apm_bios_t device_node;
+ allow apm_bios_t fs_t:filesystem associate;
+ allow apm_bios_t tmpfs_t:filesystem associate;
+ allow apm_bios_t tmp_t:filesystem associate;
+ typeattribute cardmgr_dev_t device_node;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t tmpfs_t:filesystem associate;
+ allow cardmgr_dev_t tmp_t:filesystem associate;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t noxattrfs:filesystem associate;
+ typeattribute cardmgr_dev_t file_type;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t noxattrfs:filesystem associate;
+ typeattribute cardmgr_dev_t file_type;
+ typeattribute cardmgr_dev_t polymember;
+ allow cardmgr_dev_t tmpfs_t:filesystem associate;
+ typeattribute cardmgr_dev_t tmpfile;
+ allow cardmgr_dev_t tmp_t:filesystem associate;
+ typeattribute clock_device_t device_node;
+ allow clock_device_t fs_t:filesystem associate;
+ allow clock_device_t tmpfs_t:filesystem associate;
+ allow clock_device_t tmp_t:filesystem associate;
+ typeattribute cpu_device_t device_node;
+ allow cpu_device_t fs_t:filesystem associate;
+ allow cpu_device_t tmpfs_t:filesystem associate;
+ allow cpu_device_t tmp_t:filesystem associate;
+ typeattribute crypt_device_t device_node;
+ allow crypt_device_t fs_t:filesystem associate;
+ allow crypt_device_t tmpfs_t:filesystem associate;
+ allow crypt_device_t tmp_t:filesystem associate;
+ typeattribute dri_device_t device_node;
+ allow dri_device_t fs_t:filesystem associate;
+ allow dri_device_t tmpfs_t:filesystem associate;
+ allow dri_device_t tmp_t:filesystem associate;
+ typeattribute event_device_t device_node;
+ allow event_device_t fs_t:filesystem associate;
+ allow event_device_t tmpfs_t:filesystem associate;
+ allow event_device_t tmp_t:filesystem associate;
+ typeattribute framebuf_device_t device_node;
+ allow framebuf_device_t fs_t:filesystem associate;
+ allow framebuf_device_t tmpfs_t:filesystem associate;
+ allow framebuf_device_t tmp_t:filesystem associate;
+ typeattribute lvm_control_t device_node;
+ allow lvm_control_t fs_t:filesystem associate;
+ allow lvm_control_t tmpfs_t:filesystem associate;
+ allow lvm_control_t tmp_t:filesystem associate;
+ typeattribute memory_device_t device_node;
+ allow memory_device_t fs_t:filesystem associate;
+ allow memory_device_t tmpfs_t:filesystem associate;
+ allow memory_device_t tmp_t:filesystem associate;
+neverallow ~memory_raw_read memory_device_t:{ chr_file blk_file } read;
+neverallow ~memory_raw_write memory_device_t:{ chr_file blk_file } { append write };
+ typeattribute misc_device_t device_node;
+ allow misc_device_t fs_t:filesystem associate;
+ allow misc_device_t tmpfs_t:filesystem associate;
+ allow misc_device_t tmp_t:filesystem associate;
+ typeattribute mouse_device_t device_node;
+ allow mouse_device_t fs_t:filesystem associate;
+ allow mouse_device_t tmpfs_t:filesystem associate;
+ allow mouse_device_t tmp_t:filesystem associate;
+ typeattribute mtrr_device_t device_node;
+ allow mtrr_device_t fs_t:filesystem associate;
+ allow mtrr_device_t tmpfs_t:filesystem associate;
+ allow mtrr_device_t tmp_t:filesystem associate;
+ typeattribute null_device_t device_node;
+ allow null_device_t fs_t:filesystem associate;
+ allow null_device_t tmpfs_t:filesystem associate;
+ allow null_device_t tmp_t:filesystem associate;
+ typeattribute null_device_t mlstrustedobject;
+ typeattribute power_device_t device_node;
+ allow power_device_t fs_t:filesystem associate;
+ allow power_device_t tmpfs_t:filesystem associate;
+ allow power_device_t tmp_t:filesystem associate;
+ typeattribute printer_device_t device_node;
+ allow printer_device_t fs_t:filesystem associate;
+ allow printer_device_t tmpfs_t:filesystem associate;
+ allow printer_device_t tmp_t:filesystem associate;
+ typeattribute random_device_t device_node;
+ allow random_device_t fs_t:filesystem associate;
+ allow random_device_t tmpfs_t:filesystem associate;
+ allow random_device_t tmp_t:filesystem associate;
+ typeattribute scanner_device_t device_node;
+ allow scanner_device_t fs_t:filesystem associate;
+ allow scanner_device_t tmpfs_t:filesystem associate;
+ allow scanner_device_t tmp_t:filesystem associate;
+ typeattribute sound_device_t device_node;
+ allow sound_device_t fs_t:filesystem associate;
+ allow sound_device_t tmpfs_t:filesystem associate;
+ allow sound_device_t tmp_t:filesystem associate;
+ allow sysfs_t fs_t:filesystem associate;
+ allow sysfs_t noxattrfs:filesystem associate;
+ typeattribute sysfs_t file_type;
+ typeattribute sysfs_t mountpoint;
+ typeattribute sysfs_t filesystem_type;
+ allow sysfs_t self:filesystem associate;
+ typeattribute urandom_device_t device_node;
+ allow urandom_device_t fs_t:filesystem associate;
+ allow urandom_device_t tmpfs_t:filesystem associate;
+ allow urandom_device_t tmp_t:filesystem associate;
+ allow usbfs_t fs_t:filesystem associate;
+ allow usbfs_t noxattrfs:filesystem associate;
+ typeattribute usbfs_t file_type;
+ typeattribute usbfs_t mountpoint;
+ typeattribute usbfs_t filesystem_type;
+ allow usbfs_t self:filesystem associate;
+ typeattribute usbfs_t noxattrfs;
+ typeattribute usb_device_t device_node;
+ allow usb_device_t fs_t:filesystem associate;
+ allow usb_device_t tmpfs_t:filesystem associate;
+ allow usb_device_t tmp_t:filesystem associate;
+ typeattribute v4l_device_t device_node;
+ allow v4l_device_t fs_t:filesystem associate;
+ allow v4l_device_t tmpfs_t:filesystem associate;
+ allow v4l_device_t tmp_t:filesystem associate;
+ typeattribute xserver_misc_device_t device_node;
+ allow xserver_misc_device_t fs_t:filesystem associate;
+ allow xserver_misc_device_t tmpfs_t:filesystem associate;
+ allow xserver_misc_device_t tmp_t:filesystem associate;
+ typeattribute zero_device_t device_node;
+ allow zero_device_t fs_t:filesystem associate;
+ allow zero_device_t tmpfs_t:filesystem associate;
+ allow zero_device_t tmp_t:filesystem associate;
+ typeattribute zero_device_t mlstrustedobject;
+ allow xconsole_device_t fs_t:filesystem associate;
+ allow xconsole_device_t noxattrfs:filesystem associate;
+ typeattribute xconsole_device_t file_type;
+ allow xconsole_device_t tmpfs_t:filesystem associate;
+ allow xconsole_device_t tmp_t:filesystem associate;
+ typeattribute devfs_control_t device_node;
+ allow devfs_control_t fs_t:filesystem associate;
+ allow devfs_control_t tmpfs_t:filesystem associate;
+ allow devfs_control_t tmp_t:filesystem associate;
+neverallow domain ~domain:process { transition dyntransition };
+neverallow { domain -set_curr_context } self:process setcurrent;
+neverallow { domain unlabeled_t } ~{ domain unlabeled_t }:process *;
+neverallow ~{ domain unlabeled_t } *:process *;
+allow file_type self:filesystem associate;
+ allow boot_t fs_t:filesystem associate;
+ allow boot_t noxattrfs:filesystem associate;
+ typeattribute boot_t file_type;
+ allow boot_t fs_t:filesystem associate;
+ allow boot_t noxattrfs:filesystem associate;
+ typeattribute boot_t file_type;
+ typeattribute boot_t mountpoint;
+ allow default_t fs_t:filesystem associate;
+ allow default_t noxattrfs:filesystem associate;
+ allow etc_t fs_t:filesystem associate;
+ allow etc_t noxattrfs:filesystem associate;
+ allow etc_runtime_t fs_t:filesystem associate;
+ allow etc_runtime_t noxattrfs:filesystem associate;
+ allow file_t fs_t:filesystem associate;
+ allow file_t noxattrfs:filesystem associate;
+ allow kernel_t file_t:dir mounton;
+ allow home_root_t fs_t:filesystem associate;
+ allow home_root_t noxattrfs:filesystem associate;
+ allow home_root_t fs_t:filesystem associate;
+ allow home_root_t noxattrfs:filesystem associate;
+ typeattribute home_root_t file_type;
+ typeattribute home_root_t polyparent;
+ allow lost_found_t fs_t:filesystem associate;
+ allow lost_found_t noxattrfs:filesystem associate;
+ allow mnt_t fs_t:filesystem associate;
+ allow mnt_t noxattrfs:filesystem associate;
+ allow modules_object_t fs_t:filesystem associate;
+ allow modules_object_t noxattrfs:filesystem associate;
+ typeattribute modules_object_t file_type;
+ allow no_access_t fs_t:filesystem associate;
+ allow no_access_t noxattrfs:filesystem associate;
+ allow poly_t fs_t:filesystem associate;
+ allow poly_t noxattrfs:filesystem associate;
+ allow readable_t fs_t:filesystem associate;
+ allow readable_t noxattrfs:filesystem associate;
+ allow root_t fs_t:filesystem associate;
+ allow root_t noxattrfs:filesystem associate;
+ allow root_t fs_t:filesystem associate;
+ allow root_t noxattrfs:filesystem associate;
+ typeattribute root_t file_type;
+ typeattribute root_t polyparent;
+ allow kernel_t root_t:dir mounton;
+ allow src_t fs_t:filesystem associate;
+ allow src_t noxattrfs:filesystem associate;
+ allow system_map_t fs_t:filesystem associate;
+ allow system_map_t noxattrfs:filesystem associate;
+ typeattribute system_map_t file_type;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ typeattribute tmp_t polymember;
+ allow tmp_t tmpfs_t:filesystem associate;
+ typeattribute tmp_t tmpfile;
+ allow tmp_t tmp_t:filesystem associate;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ typeattribute tmp_t polyparent;
+ allow usr_t fs_t:filesystem associate;
+ allow usr_t noxattrfs:filesystem associate;
+ allow var_t fs_t:filesystem associate;
+ allow var_t noxattrfs:filesystem associate;
+ allow var_lib_t fs_t:filesystem associate;
+ allow var_lib_t noxattrfs:filesystem associate;
+ allow var_lock_t fs_t:filesystem associate;
+ allow var_lock_t noxattrfs:filesystem associate;
+ allow var_run_t fs_t:filesystem associate;
+ allow var_run_t noxattrfs:filesystem associate;
+ allow var_spool_t fs_t:filesystem associate;
+ allow var_spool_t noxattrfs:filesystem associate;
+ typeattribute var_spool_t file_type;
+ allow var_spool_t fs_t:filesystem associate;
+ allow var_spool_t noxattrfs:filesystem associate;
+ typeattribute var_spool_t file_type;
+ typeattribute var_spool_t polymember;
+ allow var_spool_t tmpfs_t:filesystem associate;
+ typeattribute var_spool_t tmpfile;
+ allow var_spool_t tmp_t:filesystem associate;
+ typeattribute fs_t filesystem_type;
+ allow fs_t self:filesystem associate;
+ typeattribute bdev_t filesystem_type;
+ allow bdev_t self:filesystem associate;
+ typeattribute binfmt_misc_fs_t filesystem_type;
+ allow binfmt_misc_fs_t self:filesystem associate;
+ allow binfmt_misc_fs_t fs_t:filesystem associate;
+ allow binfmt_misc_fs_t noxattrfs:filesystem associate;
+ typeattribute binfmt_misc_fs_t file_type;
+ typeattribute binfmt_misc_fs_t mountpoint;
+ typeattribute capifs_t filesystem_type;
+ allow capifs_t self:filesystem associate;
+ typeattribute configfs_t filesystem_type;
+ allow configfs_t self:filesystem associate;
+ typeattribute eventpollfs_t filesystem_type;
+ allow eventpollfs_t self:filesystem associate;
+ typeattribute futexfs_t filesystem_type;
+ allow futexfs_t self:filesystem associate;
+ typeattribute hugetlbfs_t filesystem_type;
+ allow hugetlbfs_t self:filesystem associate;
+ allow hugetlbfs_t fs_t:filesystem associate;
+ allow hugetlbfs_t noxattrfs:filesystem associate;
+ typeattribute hugetlbfs_t file_type;
+ typeattribute hugetlbfs_t mountpoint;
+ typeattribute inotifyfs_t filesystem_type;
+ allow inotifyfs_t self:filesystem associate;
+ typeattribute nfsd_fs_t filesystem_type;
+ allow nfsd_fs_t self:filesystem associate;
+ typeattribute ramfs_t filesystem_type;
+ allow ramfs_t self:filesystem associate;
+ typeattribute romfs_t filesystem_type;
+ allow romfs_t self:filesystem associate;
+ typeattribute rpc_pipefs_t filesystem_type;
+ allow rpc_pipefs_t self:filesystem associate;
+ typeattribute tmpfs_t filesystem_type;
+ allow tmpfs_t self:filesystem associate;
+ allow tmpfs_t fs_t:filesystem associate;
+ allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute tmpfs_t file_type;
+ allow tmpfs_t fs_t:filesystem associate;
+ allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute tmpfs_t file_type;
+ typeattribute tmpfs_t mountpoint;
+allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute autofs_t filesystem_type;
+ allow autofs_t self:filesystem associate;
+ allow autofs_t fs_t:filesystem associate;
+ allow autofs_t noxattrfs:filesystem associate;
+ typeattribute autofs_t file_type;
+ typeattribute autofs_t mountpoint;
+ typeattribute cifs_t filesystem_type;
+ allow cifs_t self:filesystem associate;
+ typeattribute dosfs_t filesystem_type;
+ allow dosfs_t self:filesystem associate;
+allow dosfs_t fs_t:filesystem associate;
+ typeattribute iso9660_t filesystem_type;
+ allow iso9660_t self:filesystem associate;
+allow removable_t noxattrfs:filesystem associate;
+ typeattribute removable_t filesystem_type;
+ allow removable_t self:filesystem associate;
+ allow removable_t fs_t:filesystem associate;
+ allow removable_t noxattrfs:filesystem associate;
+ typeattribute removable_t file_type;
+ typeattribute removable_t usercanread;
+ typeattribute nfs_t filesystem_type;
+ allow nfs_t self:filesystem associate;
+ allow nfs_t fs_t:filesystem associate;
+ allow nfs_t noxattrfs:filesystem associate;
+ typeattribute nfs_t file_type;
+ typeattribute nfs_t mountpoint;
+neverallow ~can_load_kernmodule self:capability sys_module;
+role system_r;
+role sysadm_r;
+role staff_r;
+role user_r;
+ typeattribute kernel_t domain;
+ allow kernel_t self:dir { read getattr lock search ioctl };
+ allow kernel_t self:lnk_file { read getattr lock ioctl };
+ allow kernel_t self:file { getattr read write append ioctl lock };
+ allow kernel_t self:process { fork sigchld };
+ role secadm_r types kernel_t;
+ role sysadm_r types kernel_t;
+ role user_r types kernel_t;
+ role staff_r types kernel_t;
+ typeattribute kernel_t privrangetrans;
+role system_r types kernel_t;
+ typeattribute debugfs_t filesystem_type;
+ allow debugfs_t self:filesystem associate;
+allow debugfs_t self:filesystem associate;
+ allow proc_t fs_t:filesystem associate;
+ allow proc_t noxattrfs:filesystem associate;
+ typeattribute proc_t file_type;
+ typeattribute proc_t mountpoint;
+ typeattribute proc_t filesystem_type;
+ allow proc_t self:filesystem associate;
+neverallow ~can_receive_kernel_messages proc_kmsg_t:file ~getattr;
+neverallow { domain -kern_unconfined } proc_kcore_t:file ~getattr;
+ allow sysctl_t fs_t:filesystem associate;
+ allow sysctl_t noxattrfs:filesystem associate;
+ typeattribute sysctl_t file_type;
+ typeattribute sysctl_t mountpoint;
+ allow sysctl_fs_t fs_t:filesystem associate;
+ allow sysctl_fs_t noxattrfs:filesystem associate;
+ typeattribute sysctl_fs_t file_type;
+ typeattribute sysctl_fs_t mountpoint;
+allow kernel_t self:capability *;
+allow kernel_t unlabeled_t:dir mounton;
+allow kernel_t self:process ~{ ptrace setcurrent setexec setfscreate setrlimit execmem execstack execheap };
+allow kernel_t self:shm { associate getattr setattr create destroy read write lock unix_read unix_write };
+allow kernel_t self:sem { associate getattr setattr create destroy read write unix_read unix_write };
+allow kernel_t self:msg { send receive };
+allow kernel_t self:msgq { associate getattr setattr create destroy read write enqueue unix_read unix_write };
+allow kernel_t self:unix_dgram_socket { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } };
+allow kernel_t self:unix_stream_socket { { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } } listen accept };
+allow kernel_t self:unix_dgram_socket sendto;
+allow kernel_t self:unix_stream_socket connectto;
+allow kernel_t self:fifo_file { getattr read write append ioctl lock };
+allow kernel_t self:sock_file { read getattr lock ioctl };
+allow kernel_t self:fd use;
+allow kernel_t proc_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_t:{ lnk_file file } { read getattr lock ioctl };
+allow kernel_t proc_net_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_net_t:file { read getattr lock ioctl };
+allow kernel_t proc_mdstat_t:file { read getattr lock ioctl };
+allow kernel_t proc_kcore_t:file getattr;
+allow kernel_t proc_kmsg_t:file getattr;
+allow kernel_t sysctl_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:file { read getattr lock ioctl };
+allow kernel_t unlabeled_t:fifo_file { getattr read write append ioctl lock };
+ allow kernel_t unlabeled_t:association { sendto recvfrom };
+ allow kernel_t netif_type:netif rawip_send;
+ allow kernel_t netif_type:netif rawip_recv;
+ allow kernel_t node_type:node rawip_send;
+ allow kernel_t node_type:node rawip_recv;
+ allow kernel_t netif_t:netif rawip_send;
+ allow kernel_t netif_type:netif { tcp_send tcp_recv };
+ allow kernel_t node_type:node { tcp_send tcp_recv };
+ allow kernel_t node_t:node rawip_send;
+ allow kernel_t multicast_node_t:node rawip_send;
+ allow kernel_t sysfs_t:dir { read getattr lock search ioctl };
+ allow kernel_t sysfs_t:{ file lnk_file } { read getattr lock ioctl };
+ allow kernel_t usbfs_t:dir search;
+ allow kernel_t filesystem_type:filesystem mount;
+ allow kernel_t security_t:dir { read search getattr };
+ allow kernel_t security_t:file { getattr read write };
+ typeattribute kernel_t can_load_policy;
+ if(!secure_mode_policyload) {
+ allow kernel_t security_t:security load_policy;
+ auditallow kernel_t security_t:security load_policy;
+ }
+ allow kernel_t device_t:dir { read getattr lock search ioctl };
+ allow kernel_t device_t:lnk_file { getattr read };
+ allow kernel_t console_device_t:chr_file { getattr read write append ioctl lock };
+ allow kernel_t bin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t shell_exec_t:file { { read getattr lock execute ioctl } execute_no_trans };
+ allow kernel_t sbin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t bin_t:file { { read getattr lock execute ioctl } execute_no_trans };
+ allow kernel_t domain:process signal;
+ allow kernel_t proc_t:dir search;
+ allow kernel_t domain:dir search;
+ allow kernel_t root_t:dir { read getattr lock search ioctl };
+ allow kernel_t root_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t etc_t:dir { read getattr lock search ioctl };
+ allow kernel_t home_root_t:dir { read getattr lock search ioctl };
+ allow kernel_t usr_t:dir { read getattr lock search ioctl };
+ allow kernel_t usr_t:{ file lnk_file } { read getattr lock ioctl };
+ typeattribute kernel_t mlsprocread;
+ typeattribute kernel_t mlsprocwrite;
+ allow kernel_t self:capability *;
+ allow kernel_t self:fifo_file { create ioctl read getattr lock write setattr append link unlink rename };
+ allow kernel_t self:process transition;
+ allow kernel_t self:file { getattr read write append ioctl lock };
+ allow kernel_t self:nscd *;
+ allow kernel_t self:dbus *;
+ allow kernel_t self:passwd *;
+ allow kernel_t proc_type:{ dir file } *;
+ allow kernel_t sysctl_t:{ dir file } *;
+ allow kernel_t kernel_t:system *;
+ allow kernel_t unlabeled_t:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+ allow kernel_t unlabeled_t:filesystem *;
+ allow kernel_t unlabeled_t:association *;
+ typeattribute kernel_t can_load_kernmodule, can_receive_kernel_messages;
+ typeattribute kernel_t kern_unconfined;
+ allow kernel_t { proc_t proc_net_t }:dir search;
+ allow kernel_t sysctl_type:dir { read getattr lock search ioctl };
+ allow kernel_t sysctl_type:file { { getattr read write append ioctl lock } setattr };
+ allow kernel_t node_type:node *;
+ allow kernel_t netif_type:netif *;
+ allow kernel_t port_type:tcp_socket { send_msg recv_msg name_connect };
+ allow kernel_t port_type:udp_socket { send_msg recv_msg };
+ allow kernel_t port_type:{ tcp_socket udp_socket rawip_socket } name_bind;
+ allow kernel_t node_type:{ tcp_socket udp_socket rawip_socket } node_bind;
+ allow kernel_t unlabeled_t:association { sendto recvfrom };
+ allow kernel_t device_node:{ chr_file blk_file } *;
+ allow kernel_t mtrr_device_t:{ dir file } *;
+ allow kernel_t self:capability sys_rawio;
+ typeattribute kernel_t memory_raw_write, memory_raw_read;
+ typeattribute kernel_t unconfined_domain_type;
+ typeattribute kernel_t can_change_process_identity;
+ typeattribute kernel_t can_change_process_role;
+ typeattribute kernel_t can_change_object_identity;
+ typeattribute kernel_t set_curr_context;
+ allow kernel_t domain:{ { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } socket key_socket } *;
+ allow kernel_t domain:fd use;
+ allow kernel_t domain:fifo_file { getattr read write append ioctl lock };
+ allow kernel_t domain:process ~{ transition dyntransition execmem execstack execheap };
+ allow kernel_t domain:{ sem msgq shm } *;
+ allow kernel_t domain:msg { send receive };
+ allow kernel_t domain:dir { read getattr lock search ioctl };
+ allow kernel_t domain:file { read getattr lock ioctl };
+ allow kernel_t domain:lnk_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:dir { read getattr lock search ioctl };
+ dontaudit kernel_t domain:lnk_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:file { read getattr lock ioctl };
+ dontaudit kernel_t domain:sock_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:fifo_file { read getattr lock ioctl };
+ allow kernel_t file_type:{ file chr_file } ~execmod;
+ allow kernel_t file_type:{ dir lnk_file sock_file fifo_file blk_file } *;
+ allow kernel_t file_type:filesystem *;
+ allow kernel_t file_type:{ unix_stream_socket unix_dgram_socket } name_bind;
+ if (allow_execmod) {
+ allow kernel_t file_type:file execmod;
+ }
+ allow kernel_t filesystem_type:filesystem *;
+ allow kernel_t filesystem_type:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+ allow kernel_t security_t:dir { getattr search read };
+ allow kernel_t security_t:file { getattr read write };
+ typeattribute kernel_t can_load_policy, can_setenforce, can_setsecparam;
+ if(!secure_mode_policyload) {
+ allow kernel_t security_t:security *;
+ auditallow kernel_t security_t:security { load_policy setenforce setbool };
+ }
+ if (allow_execheap) {
+ allow kernel_t self:process execheap;
+ }
+ if (allow_execmem) {
+ allow kernel_t self:process execmem;
+ }
+ if (allow_execmem && allow_execstack) {
+ allow kernel_t self:process execstack;
+ auditallow kernel_t self:process execstack;
+ } else {
+ }
+ if (allow_execheap) {
+ auditallow kernel_t self:process execheap;
+ }
+ if (allow_execmem) {
+ auditallow kernel_t self:process execmem;
+ }
+ if (read_default_t) {
+ allow kernel_t default_t:dir { read getattr lock search ioctl };
+ allow kernel_t default_t:file { read getattr lock ioctl };
+ allow kernel_t default_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t default_t:sock_file { read getattr lock ioctl };
+ allow kernel_t default_t:fifo_file { read getattr lock ioctl };
+ }
+ allow unlabeled_t self:filesystem associate;
+range_transition getty_t login_exec_t s0 - s0:c0.c255;
+range_transition init_t xdm_exec_t s0 - s0:c0.c255;
+range_transition initrc_t crond_exec_t s0 - s0:c0.c255;
+range_transition initrc_t cupsd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t sshd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t udev_exec_t s0 - s0:c0.c255;
+range_transition initrc_t xdm_exec_t s0 - s0:c0.c255;
+range_transition kernel_t udev_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t su_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t initrc_exec_t s0;
+ typeattribute security_t filesystem_type;
+ allow security_t self:filesystem associate;
+ typeattribute security_t mlstrustedobject;
+neverallow ~can_load_policy security_t:security load_policy;
+neverallow ~can_setenforce security_t:security setenforce;
+neverallow ~can_setsecparam security_t:security setsecparam;
+ typeattribute bsdpty_device_t device_node;
+ allow bsdpty_device_t fs_t:filesystem associate;
+ allow bsdpty_device_t tmpfs_t:filesystem associate;
+ allow bsdpty_device_t tmp_t:filesystem associate;
+ typeattribute console_device_t device_node;
+ allow console_device_t fs_t:filesystem associate;
+ allow console_device_t tmpfs_t:filesystem associate;
+ allow console_device_t tmp_t:filesystem associate;
+ allow devpts_t fs_t:filesystem associate;
+ allow devpts_t noxattrfs:filesystem associate;
+ typeattribute devpts_t file_type;
+ typeattribute devpts_t mountpoint;
+ allow devpts_t tmpfs_t:filesystem associate;
+ allow devpts_t tmp_t:filesystem associate;
+ typeattribute devpts_t filesystem_type;
+ allow devpts_t self:filesystem associate;
+ typeattribute devpts_t ttynode, ptynode;
+ typeattribute devtty_t device_node;
+ allow devtty_t fs_t:filesystem associate;
+ allow devtty_t tmpfs_t:filesystem associate;
+ allow devtty_t tmp_t:filesystem associate;
+ typeattribute devtty_t mlstrustedobject;
+ typeattribute ptmx_t device_node;
+ allow ptmx_t fs_t:filesystem associate;
+ allow ptmx_t tmpfs_t:filesystem associate;
+ allow ptmx_t tmp_t:filesystem associate;
+ typeattribute ptmx_t mlstrustedobject;
+ typeattribute tty_device_t device_node;
+ allow tty_device_t fs_t:filesystem associate;
+ allow tty_device_t tmpfs_t:filesystem associate;
+ allow tty_device_t tmp_t:filesystem associate;
+ typeattribute tty_device_t ttynode;
+ typeattribute usbtty_device_t device_node;
+ allow usbtty_device_t fs_t:filesystem associate;
+ allow usbtty_device_t tmpfs_t:filesystem associate;
+ allow usbtty_device_t tmp_t:filesystem associate;
+user system_u roles { system_r } level s0 range s0 - s0:c0.c255;
+user user_u roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+ user root roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+constrain process transition
+ ( u1 == u2
+ or t1 == can_change_process_identity
+);
+constrain process transition
+ ( r1 == r2
+ or t1 == can_change_process_role
+);
+constrain process dyntransition
+ ( u1 == u2 and r1 == r2 );
+constrain { dir file lnk_file sock_file fifo_file chr_file blk_file } { create relabelto relabelfrom }
+ ( u1 == u2 or t1 == can_change_object_identity );
+constrain { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } { create relabelto relabelfrom }
+ ( u1 == u2 or t1 == can_change_object_identity );
+sid port system_u:object_r:port_t:s0
+sid node system_u:object_r:node_t:s0
+sid netif system_u:object_r:netif_t:s0
+sid devnull system_u:object_r:null_device_t:s0
+sid file system_u:object_r:file_t:s0
+sid fs system_u:object_r:fs_t:s0
+sid kernel system_u:system_r:kernel_t:s0
+sid sysctl system_u:object_r:sysctl_t:s0
+sid unlabeled system_u:object_r:unlabeled_t:s0
+sid any_socket system_u:object_r:unlabeled_t:s0
+sid file_labels system_u:object_r:unlabeled_t:s0
+sid icmp_socket system_u:object_r:unlabeled_t:s0
+sid igmp_packet system_u:object_r:unlabeled_t:s0
+sid init system_u:object_r:unlabeled_t:s0
+sid kmod system_u:object_r:unlabeled_t:s0
+sid netmsg system_u:object_r:unlabeled_t:s0
+sid policy system_u:object_r:unlabeled_t:s0
+sid scmp_packet system_u:object_r:unlabeled_t:s0
+sid sysctl_modprobe system_u:object_r:unlabeled_t:s0
+sid sysctl_fs system_u:object_r:unlabeled_t:s0
+sid sysctl_kernel system_u:object_r:unlabeled_t:s0
+sid sysctl_net system_u:object_r:unlabeled_t:s0
+sid sysctl_net_unix system_u:object_r:unlabeled_t:s0
+sid sysctl_vm system_u:object_r:unlabeled_t:s0
+sid sysctl_dev system_u:object_r:unlabeled_t:s0
+sid tcp_socket system_u:object_r:unlabeled_t:s0
+sid security system_u:object_r:security_t:s0
+fs_use_xattr ext2 system_u:object_r:fs_t:s0;
+fs_use_xattr ext3 system_u:object_r:fs_t:s0;
+fs_use_xattr gfs system_u:object_r:fs_t:s0;
+fs_use_xattr jfs system_u:object_r:fs_t:s0;
+fs_use_xattr reiserfs system_u:object_r:fs_t:s0;
+fs_use_xattr xfs system_u:object_r:fs_t:s0;
+fs_use_task pipefs system_u:object_r:fs_t:s0;
+fs_use_task sockfs system_u:object_r:fs_t:s0;
+fs_use_trans mqueue system_u:object_r:tmpfs_t:s0;
+fs_use_trans shm system_u:object_r:tmpfs_t:s0;
+fs_use_trans tmpfs system_u:object_r:tmpfs_t:s0;
+fs_use_trans devpts system_u:object_r:devpts_t:s0;
+genfscon proc /mtrr system_u:object_r:mtrr_device_t:s0
+genfscon sysfs / system_u:object_r:sysfs_t:s0
+genfscon usbfs / system_u:object_r:usbfs_t:s0
+genfscon usbdevfs / system_u:object_r:usbfs_t:s0
+genfscon rootfs / system_u:object_r:root_t:s0
+genfscon bdev / system_u:object_r:bdev_t:s0
+genfscon binfmt_misc / system_u:object_r:binfmt_misc_fs_t:s0
+genfscon capifs / system_u:object_r:capifs_t:s0
+genfscon configfs / system_u:object_r:configfs_t:s0
+genfscon eventpollfs / system_u:object_r:eventpollfs_t:s0
+genfscon futexfs / system_u:object_r:futexfs_t:s0
+genfscon hugetlbfs / system_u:object_r:hugetlbfs_t:s0
+genfscon inotifyfs / system_u:object_r:inotifyfs_t:s0
+genfscon nfsd / system_u:object_r:nfsd_fs_t:s0
+genfscon ramfs / system_u:object_r:ramfs_t:s0
+genfscon romfs / system_u:object_r:romfs_t:s0
+genfscon cramfs / system_u:object_r:romfs_t:s0
+genfscon rpc_pipefs / system_u:object_r:rpc_pipefs_t:s0
+genfscon autofs / system_u:object_r:autofs_t:s0
+genfscon automount / system_u:object_r:autofs_t:s0
+genfscon cifs / system_u:object_r:cifs_t:s0
+genfscon smbfs / system_u:object_r:cifs_t:s0
+genfscon fat / system_u:object_r:dosfs_t:s0
+genfscon msdos / system_u:object_r:dosfs_t:s0
+genfscon ntfs / system_u:object_r:dosfs_t:s0
+genfscon vfat / system_u:object_r:dosfs_t:s0
+genfscon iso9660 / system_u:object_r:iso9660_t:s0
+genfscon udf / system_u:object_r:iso9660_t:s0
+genfscon nfs / system_u:object_r:nfs_t:s0
+genfscon nfs4 / system_u:object_r:nfs_t:s0
+genfscon afs / system_u:object_r:nfs_t:s0
+genfscon hfsplus / system_u:object_r:nfs_t:s0
+genfscon debugfs / system_u:object_r:debugfs_t:s0
+genfscon proc / system_u:object_r:proc_t:s0
+genfscon proc /sysvipc system_u:object_r:proc_t:s0
+genfscon proc /kmsg system_u:object_r:proc_kmsg_t:s0
+genfscon proc /kcore system_u:object_r:proc_kcore_t:s0
+genfscon proc /mdstat system_u:object_r:proc_mdstat_t:s0
+genfscon proc /net system_u:object_r:proc_net_t:s0
+genfscon proc /xen system_u:object_r:proc_xen_t:s0
+genfscon proc /sys system_u:object_r:sysctl_t:s0
+genfscon proc /irq system_u:object_r:sysctl_irq_t:s0
+genfscon proc /net/rpc system_u:object_r:sysctl_rpc_t:s0
+genfscon proc /sys/fs system_u:object_r:sysctl_fs_t:s0
+genfscon proc /sys/kernel system_u:object_r:sysctl_kernel_t:s0
+genfscon proc /sys/kernel/modprobe system_u:object_r:sysctl_modprobe_t:s0
+genfscon proc /sys/kernel/hotplug system_u:object_r:sysctl_hotplug_t:s0
+genfscon proc /sys/net system_u:object_r:sysctl_net_t:s0
+genfscon proc /sys/net/unix system_u:object_r:sysctl_net_unix_t:s0
+genfscon proc /sys/vm system_u:object_r:sysctl_vm_t:s0
+genfscon proc /sys/dev system_u:object_r:sysctl_dev_t:s0
+genfscon selinuxfs / system_u:object_r:security_t:s0
+portcon udp 7007 system_u:object_r:afs_bos_port_t:s0
+portcon tcp 2040 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7000 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7005 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7004 system_u:object_r:afs_ka_port_t:s0
+portcon udp 7002 system_u:object_r:afs_pt_port_t:s0
+portcon udp 7003 system_u:object_r:afs_vl_port_t:s0
+portcon udp 10080 system_u:object_r:amanda_port_t:s0
+portcon tcp 10080 system_u:object_r:amanda_port_t:s0
+portcon udp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10082 system_u:object_r:amanda_port_t:s0
+portcon tcp 10083 system_u:object_r:amanda_port_t:s0
+portcon tcp 10024 system_u:object_r:amavisd_recv_port_t:s0
+portcon tcp 10025 system_u:object_r:amavisd_send_port_t:s0
+portcon tcp 1720 system_u:object_r:asterisk_port_t:s0
+portcon udp 2427 system_u:object_r:asterisk_port_t:s0
+portcon udp 2727 system_u:object_r:asterisk_port_t:s0
+portcon udp 4569 system_u:object_r:asterisk_port_t:s0
+portcon udp 5060 system_u:object_r:asterisk_port_t:s0
+portcon tcp 113 system_u:object_r:auth_port_t:s0
+portcon tcp 179 system_u:object_r:bgp_port_t:s0
+portcon udp 179 system_u:object_r:bgp_port_t:s0
+portcon tcp 3310 system_u:object_r:clamd_port_t:s0
+portcon udp 4041 system_u:object_r:clockspeed_port_t:s0
+portcon udp 512 system_u:object_r:comsat_port_t:s0
+portcon tcp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 6276 system_u:object_r:dcc_port_t:s0
+portcon udp 6277 system_u:object_r:dcc_port_t:s0
+portcon tcp 1178 system_u:object_r:dbskkd_port_t:s0
+portcon udp 68 system_u:object_r:dhcpc_port_t:s0
+portcon udp 67 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 647 system_u:object_r:dhcpd_port_t:s0
+portcon udp 647 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 847 system_u:object_r:dhcpd_port_t:s0
+portcon udp 847 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 2628 system_u:object_r:dict_port_t:s0
+portcon tcp 3632 system_u:object_r:distccd_port_t:s0
+portcon udp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 79 system_u:object_r:fingerd_port_t:s0
+portcon tcp 20 system_u:object_r:ftp_data_port_t:s0
+portcon tcp 21 system_u:object_r:ftp_port_t:s0
+portcon udp 1718 system_u:object_r:gatekeeper_port_t:s0
+portcon udp 1719 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1721 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 7000 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1213 system_u:object_r:giftd_port_t:s0
+portcon tcp 70 system_u:object_r:gopher_port_t:s0
+portcon udp 70 system_u:object_r:gopher_port_t:s0
+portcon tcp 3128 system_u:object_r:http_cache_port_t:s0
+portcon udp 3130 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8080 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8118 system_u:object_r:http_cache_port_t:s0
+portcon tcp 80 system_u:object_r:http_port_t:s0
+portcon tcp 443 system_u:object_r:http_port_t:s0
+portcon tcp 488 system_u:object_r:http_port_t:s0
+portcon tcp 8008 system_u:object_r:http_port_t:s0
+portcon tcp 9050 system_u:object_r:http_port_t:s0
+portcon tcp 5335 system_u:object_r:howl_port_t:s0
+portcon udp 5353 system_u:object_r:howl_port_t:s0
+portcon tcp 50000 system_u:object_r:hplip_port_t:s0
+portcon tcp 50002 system_u:object_r:hplip_port_t:s0
+portcon tcp 9010 system_u:object_r:i18n_input_port_t:s0
+portcon tcp 5323 system_u:object_r:imaze_port_t:s0
+portcon udp 5323 system_u:object_r:imaze_port_t:s0
+portcon tcp 7 system_u:object_r:inetd_child_port_t:s0
+portcon udp 7 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 9 system_u:object_r:inetd_child_port_t:s0
+portcon udp 9 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 13 system_u:object_r:inetd_child_port_t:s0
+portcon udp 13 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 19 system_u:object_r:inetd_child_port_t:s0
+portcon udp 19 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 37 system_u:object_r:inetd_child_port_t:s0
+portcon udp 37 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 512 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 543 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 544 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 891 system_u:object_r:inetd_child_port_t:s0
+portcon udp 891 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 892 system_u:object_r:inetd_child_port_t:s0
+portcon udp 892 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 2105 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 5666 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 119 system_u:object_r:innd_port_t:s0
+portcon tcp 631 system_u:object_r:ipp_port_t:s0
+portcon udp 631 system_u:object_r:ipp_port_t:s0
+portcon tcp 6667 system_u:object_r:ircd_port_t:s0
+portcon udp 500 system_u:object_r:isakmp_port_t:s0
+portcon tcp 5222 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5223 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5269 system_u:object_r:jabber_interserver_port_t:s0
+portcon tcp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon udp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 749 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon udp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon tcp 88 system_u:object_r:kerberos_port_t:s0
+portcon udp 88 system_u:object_r:kerberos_port_t:s0
+portcon tcp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 517 system_u:object_r:ktalkd_port_t:s0
+portcon udp 518 system_u:object_r:ktalkd_port_t:s0
+portcon tcp 389 system_u:object_r:ldap_port_t:s0
+portcon udp 389 system_u:object_r:ldap_port_t:s0
+portcon tcp 636 system_u:object_r:ldap_port_t:s0
+portcon udp 636 system_u:object_r:ldap_port_t:s0
+portcon tcp 2000 system_u:object_r:mail_port_t:s0
+portcon tcp 1234 system_u:object_r:monopd_port_t:s0
+portcon tcp 3306 system_u:object_r:mysqld_port_t:s0
+portcon tcp 1241 system_u:object_r:nessus_port_t:s0
+portcon udp 137 system_u:object_r:nmbd_port_t:s0
+portcon udp 138 system_u:object_r:nmbd_port_t:s0
+portcon udp 139 system_u:object_r:nmbd_port_t:s0
+portcon udp 123 system_u:object_r:ntp_port_t:s0
+portcon udp 5000 system_u:object_r:openvpn_port_t:s0
+portcon tcp 5988 system_u:object_r:pegasus_http_port_t:s0
+portcon tcp 5989 system_u:object_r:pegasus_https_port_t:s0
+portcon tcp 106 system_u:object_r:pop_port_t:s0
+portcon tcp 109 system_u:object_r:pop_port_t:s0
+portcon tcp 110 system_u:object_r:pop_port_t:s0
+portcon tcp 143 system_u:object_r:pop_port_t:s0
+portcon tcp 220 system_u:object_r:pop_port_t:s0
+portcon tcp 993 system_u:object_r:pop_port_t:s0
+portcon tcp 995 system_u:object_r:pop_port_t:s0
+portcon tcp 1109 system_u:object_r:pop_port_t:s0
+portcon udp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 5432 system_u:object_r:postgresql_port_t:s0
+portcon tcp 60000 system_u:object_r:postgrey_port_t:s0
+portcon tcp 515 system_u:object_r:printer_port_t:s0
+portcon tcp 5703 system_u:object_r:ptal_port_t:s0
+portcon udp 4011 system_u:object_r:pxe_port_t:s0
+portcon udp 24441 system_u:object_r:pyzor_port_t:s0
+portcon udp 1646 system_u:object_r:radacct_port_t:s0
+portcon udp 1813 system_u:object_r:radacct_port_t:s0
+portcon udp 1645 system_u:object_r:radius_port_t:s0
+portcon udp 1812 system_u:object_r:radius_port_t:s0
+portcon tcp 2703 system_u:object_r:razor_port_t:s0
+portcon tcp 513 system_u:object_r:rlogind_port_t:s0
+portcon tcp 953 system_u:object_r:rndc_port_t:s0
+portcon udp 520 system_u:object_r:router_port_t:s0
+portcon tcp 514 system_u:object_r:rsh_port_t:s0
+portcon tcp 873 system_u:object_r:rsync_port_t:s0
+portcon udp 873 system_u:object_r:rsync_port_t:s0
+portcon tcp 137-139 system_u:object_r:smbd_port_t:s0
+portcon tcp 445 system_u:object_r:smbd_port_t:s0
+portcon tcp 25 system_u:object_r:smtp_port_t:s0
+portcon tcp 465 system_u:object_r:smtp_port_t:s0
+portcon tcp 587 system_u:object_r:smtp_port_t:s0
+portcon udp 161 system_u:object_r:snmp_port_t:s0
+portcon udp 162 system_u:object_r:snmp_port_t:s0
+portcon tcp 199 system_u:object_r:snmp_port_t:s0
+portcon tcp 783 system_u:object_r:spamd_port_t:s0
+portcon tcp 22 system_u:object_r:ssh_port_t:s0
+portcon tcp 8000 system_u:object_r:soundd_port_t:s0
+portcon tcp 9433 system_u:object_r:soundd_port_t:s0
+portcon tcp 901 system_u:object_r:swat_port_t:s0
+portcon udp 514 system_u:object_r:syslogd_port_t:s0
+portcon tcp 23 system_u:object_r:telnetd_port_t:s0
+portcon udp 69 system_u:object_r:tftp_port_t:s0
+portcon tcp 8081 system_u:object_r:transproxy_port_t:s0
+portcon tcp 540 system_u:object_r:uucpd_port_t:s0
+portcon tcp 5900 system_u:object_r:vnc_port_t:s0
+portcon tcp 6001 system_u:object_r:xserver_port_t:s0
+portcon tcp 6002 system_u:object_r:xserver_port_t:s0
+portcon tcp 6003 system_u:object_r:xserver_port_t:s0
+portcon tcp 6004 system_u:object_r:xserver_port_t:s0
+portcon tcp 6005 system_u:object_r:xserver_port_t:s0
+portcon tcp 6006 system_u:object_r:xserver_port_t:s0
+portcon tcp 6007 system_u:object_r:xserver_port_t:s0
+portcon tcp 6008 system_u:object_r:xserver_port_t:s0
+portcon tcp 6009 system_u:object_r:xserver_port_t:s0
+portcon tcp 6010 system_u:object_r:xserver_port_t:s0
+portcon tcp 6011 system_u:object_r:xserver_port_t:s0
+portcon tcp 6012 system_u:object_r:xserver_port_t:s0
+portcon tcp 6013 system_u:object_r:xserver_port_t:s0
+portcon tcp 6014 system_u:object_r:xserver_port_t:s0
+portcon tcp 6015 system_u:object_r:xserver_port_t:s0
+portcon tcp 6016 system_u:object_r:xserver_port_t:s0
+portcon tcp 6017 system_u:object_r:xserver_port_t:s0
+portcon tcp 6018 system_u:object_r:xserver_port_t:s0
+portcon tcp 6019 system_u:object_r:xserver_port_t:s0
+portcon tcp 8002 system_u:object_r:xen_port_t:s0
+portcon tcp 2601 system_u:object_r:zebra_port_t:s0
+portcon tcp 8021 system_u:object_r:zope_port_t:s0
+portcon tcp 1-1023 system_u:object_r:reserved_port_t:s0
+portcon udp 1-1023 system_u:object_r:reserved_port_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:compat_ipv4_node_t:s0
+nodecon 0.0.0.0 255.255.255.255 system_u:object_r:inaddr_any_node_t:s0
+nodecon fe80:: ffff:ffff:ffff:ffff:: system_u:object_r:link_local_node_t:s0
+nodecon 127.0.0.1 255.255.255.255 system_u:object_r:lo_node_t:s0
+nodecon ::ffff:0000:0000 ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:mapped_ipv4_node_t:s0
+nodecon ff00:: ff00:: system_u:object_r:multicast_node_t:s0
+nodecon fec0:: ffc0:: system_u:object_r:site_local_node_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system_u:object_r:unspec_node_t:s0
diff --git a/tests/policies/test-deps/base-metreq.conf b/tests/policies/test-deps/base-metreq.conf
new file mode 100644
index 0000000..9b7ade5
--- /dev/null
+++ b/tests/policies/test-deps/base-metreq.conf
@@ -0,0 +1,519 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+
+# Make this decl easy to find
+type base_global_decl_t;
+
+# Actually used in module tests
+type type_req_t;
+attribute attr_req;
+bool bool_req false;
+role role_req_r;
+
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/tests/policies/test-deps/base-notmetreq.conf b/tests/policies/test-deps/base-notmetreq.conf
new file mode 100644
index 0000000..cf6aa0a
--- /dev/null
+++ b/tests/policies/test-deps/base-notmetreq.conf
@@ -0,0 +1,506 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/tests/policies/test-deps/modreq-attr-global.conf b/tests/policies/test-deps/modreq-attr-global.conf
new file mode 100644
index 0000000..92f6b30
--- /dev/null
+++ b/tests/policies/test-deps/modreq-attr-global.conf
@@ -0,0 +1,10 @@
+module modreq_attr_global 1.0;
+
+require {
+ attribute attr_req;
+}
+
+type mod_global_t;
+
+type new_t, attr_req;
+
diff --git a/tests/policies/test-deps/modreq-attr-opt.conf b/tests/policies/test-deps/modreq-attr-opt.conf
new file mode 100644
index 0000000..b970c1d
--- /dev/null
+++ b/tests/policies/test-deps/modreq-attr-opt.conf
@@ -0,0 +1,16 @@
+module modreq_attr_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ attribute attr_req;
+ }
+ type mod_opt_t;
+ type new_t, attr_req;
+}
diff --git a/tests/policies/test-deps/modreq-bool-global.conf b/tests/policies/test-deps/modreq-bool-global.conf
new file mode 100644
index 0000000..4ef0cc9
--- /dev/null
+++ b/tests/policies/test-deps/modreq-bool-global.conf
@@ -0,0 +1,15 @@
+module modreq_bool_global 1.0;
+
+require {
+ bool bool_req;
+ class file { read write };
+}
+
+type mod_global_t;
+
+type a_t;
+type b_t;
+
+if (bool_req) {
+ allow a_t b_t : file { read write };
+}
diff --git a/tests/policies/test-deps/modreq-bool-opt.conf b/tests/policies/test-deps/modreq-bool-opt.conf
new file mode 100644
index 0000000..27af4f2
--- /dev/null
+++ b/tests/policies/test-deps/modreq-bool-opt.conf
@@ -0,0 +1,22 @@
+module modreq_bool_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ bool bool_req;
+ }
+
+ type a_t;
+ type b_t;
+ type mod_opt_t;
+
+ if (bool_req) {
+ allow a_t b_t : file { read write };
+ }
+}
diff --git a/tests/policies/test-deps/modreq-obj-global.conf b/tests/policies/test-deps/modreq-obj-global.conf
new file mode 100644
index 0000000..e9eba77
--- /dev/null
+++ b/tests/policies/test-deps/modreq-obj-global.conf
@@ -0,0 +1,13 @@
+module modreq_obj_global 1.0;
+
+require {
+ class sem { create destroy };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+allow mod_foo_t mod_bar_t : sem { create destroy };
+
diff --git a/tests/policies/test-deps/modreq-obj-opt.conf b/tests/policies/test-deps/modreq-obj-opt.conf
new file mode 100644
index 0000000..67a41a4
--- /dev/null
+++ b/tests/policies/test-deps/modreq-obj-opt.conf
@@ -0,0 +1,20 @@
+module modreq_obj_global 1.0;
+
+require {
+ class file { read };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+optional {
+ require {
+ class sem { create destroy };
+ }
+
+ type mod_opt_t;
+
+ allow mod_foo_t mod_bar_t : sem { create destroy };
+}
diff --git a/tests/policies/test-deps/modreq-perm-global.conf b/tests/policies/test-deps/modreq-perm-global.conf
new file mode 100644
index 0000000..941ca96
--- /dev/null
+++ b/tests/policies/test-deps/modreq-perm-global.conf
@@ -0,0 +1,10 @@
+module modreq_perm_global 1.0;
+
+require {
+ class msg { send receive };
+}
+
+type mod_global_t;
+type a_t;
+type b_t;
+allow a_t b_t: msg { send receive };
diff --git a/tests/policies/test-deps/modreq-perm-opt.conf b/tests/policies/test-deps/modreq-perm-opt.conf
new file mode 100644
index 0000000..43a3f97
--- /dev/null
+++ b/tests/policies/test-deps/modreq-perm-opt.conf
@@ -0,0 +1,18 @@
+module modreq_perm_opt 1.0;
+
+require {
+ class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ class msg { send receive };
+ }
+
+ type mod_opt_t;
+ type a_mod_t;
+ type b_mod_t;
+ allow a_mod_t b_mod_t: msg { send receive };
+}
diff --git a/tests/policies/test-deps/modreq-role-global.conf b/tests/policies/test-deps/modreq-role-global.conf
new file mode 100644
index 0000000..01fd3ec
--- /dev/null
+++ b/tests/policies/test-deps/modreq-role-global.conf
@@ -0,0 +1,13 @@
+module modreq_role_global 1.0;
+
+require {
+ role role_req_r, user_r;
+}
+
+type mod_global_t;
+
+type a_t;
+
+# role role_req_r types a_t;
+allow role_req_r user_r;
+
diff --git a/tests/policies/test-deps/modreq-role-opt.conf b/tests/policies/test-deps/modreq-role-opt.conf
new file mode 100644
index 0000000..532a77e
--- /dev/null
+++ b/tests/policies/test-deps/modreq-role-opt.conf
@@ -0,0 +1,17 @@
+module modreq_role_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ role role_req_r, user_r;
+ }
+ type mod_opt_t;
+
+ allow role_req_r user_r;
+}
diff --git a/tests/policies/test-deps/modreq-type-global.conf b/tests/policies/test-deps/modreq-type-global.conf
new file mode 100644
index 0000000..e5704a3
--- /dev/null
+++ b/tests/policies/test-deps/modreq-type-global.conf
@@ -0,0 +1,12 @@
+module modreq_type_global 1.0;
+
+require {
+ type type_req_t;
+ class file { read write };
+}
+
+type mod_global_t;
+
+type test_t;
+
+allow test_t type_req_t : file { read write };
diff --git a/tests/policies/test-deps/modreq-type-opt.conf b/tests/policies/test-deps/modreq-type-opt.conf
new file mode 100644
index 0000000..65071d7
--- /dev/null
+++ b/tests/policies/test-deps/modreq-type-opt.conf
@@ -0,0 +1,16 @@
+module modreq_type_opt 1.0;
+
+require {
+ type file_t;
+ class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ type type_req_t;
+ }
+ type mod_opt_t;
+ allow type_req_t file_t : file { read write };
+} \ No newline at end of file
diff --git a/tests/policies/test-deps/module.conf b/tests/policies/test-deps/module.conf
new file mode 100644
index 0000000..1971e4c
--- /dev/null
+++ b/tests/policies/test-deps/module.conf
@@ -0,0 +1,20 @@
+module my_module 1.0;
+
+require {
+ bool secure_mode;
+ type system_t, sysadm_t, file_t;
+ attribute domain;
+ role system_r;
+ class file {read write};
+
+}
+
+type new_t, domain;
+role system_r types new_t;
+
+allow system_t file_t : file { read write };
+
+if (secure_mode)
+{
+ allow sysadm_t file_t : file { read write };
+}
diff --git a/tests/policies/test-deps/small-base.conf b/tests/policies/test-deps/small-base.conf
new file mode 100644
index 0000000..7c1cbe4
--- /dev/null
+++ b/tests/policies/test-deps/small-base.conf
@@ -0,0 +1,511 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/tests/policies/test-expander/alias-base.conf b/tests/policies/test-expander/alias-base.conf
new file mode 100644
index 0000000..f3d0a6c
--- /dev/null
+++ b/tests/policies/test-expander/alias-base.conf
@@ -0,0 +1,498 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+type enable_optional;
+
+# Alias tests
+type alias_check_1_t;
+type alias_check_2_t;
+type alias_check_3_t;
+
+typealias alias_check_1_t alias alias_check_1_a;
+
+optional {
+ require {
+ type alias_check_2_t;
+ }
+ typealias alias_check_2_t alias alias_check_2_a;
+}
+
+optional {
+ require {
+ type alias_check_3_a;
+ }
+ allow alias_check_3_a enable_optional:file read;
+}
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/tests/policies/test-expander/alias-module.conf b/tests/policies/test-expander/alias-module.conf
new file mode 100644
index 0000000..72d791e
--- /dev/null
+++ b/tests/policies/test-expander/alias-module.conf
@@ -0,0 +1,8 @@
+module my_module 1.0;
+
+require {
+ type alias_check_3_t;
+}
+
+typealias alias_check_3_t alias alias_check_3_a;
+
diff --git a/tests/policies/test-expander/base-base-only.conf b/tests/policies/test-expander/base-base-only.conf
new file mode 100644
index 0000000..80b87cc
--- /dev/null
+++ b/tests/policies/test-expander/base-base-only.conf
@@ -0,0 +1,43 @@
+class security
+class file
+
+sid kernel
+
+common file
+{
+ read
+}
+
+class file
+inherits file
+{
+ entrypoint
+}
+
+class security
+{
+ compute_av
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+dominance { s0 }
+
+category c0;
+
+level s0:c0;
+
+mlsconstrain file { read }
+ ( h1 dom h2 );
+')
+
+attribute myattr;
+type mytype_t;
+role myrole_r types mytype_t;
+bool mybool true;
+gen_user(myuser_u,, myrole_r, s0, s0 - s0:c0)
+
+sid kernel gen_context(myuser_u:myrole_r:mytype_t, s0)
+
+
diff --git a/tests/policies/test-expander/module.conf b/tests/policies/test-expander/module.conf
new file mode 100644
index 0000000..6186db7
--- /dev/null
+++ b/tests/policies/test-expander/module.conf
@@ -0,0 +1,228 @@
+module my_module 1.0;
+
+require {
+ bool allow_ypbind, secure_mode, allow_execstack;
+ type system_t, sysadm_t;
+ class file {read write};
+ attribute attr_check_base_2, attr_check_base_3;
+ attribute attr_check_base_optional_2;
+}
+
+bool module_1_bool true;
+
+if (module_1_bool && allow_ypbind && secure_mode && allow_execstack) {
+ allow system_t sysadm_t : file { read write };
+}
+
+optional {
+ bool module_1_bool_2 false;
+ require {
+ bool optional_bool_1, optional_bool_2;
+ class file { execute ioctl };
+ }
+ if (optional_bool_1 && optional_bool_2 || module_1_bool_2) {
+ allow system_t sysadm_t : file {execute ioctl};
+ }
+}
+# Type - attribute mapping test
+type module_t;
+attribute attr_check_mod_1;
+attribute attr_check_mod_2;
+attribute attr_check_mod_3;
+attribute attr_check_mod_4;
+attribute attr_check_mod_5;
+attribute attr_check_mod_6;
+attribute attr_check_mod_7;
+attribute attr_check_mod_8;
+attribute attr_check_mod_9;
+attribute attr_check_mod_10;
+attribute attr_check_mod_11;
+optional {
+ require {
+ type base_t;
+ }
+ attribute attr_check_mod_optional_1;
+ attribute attr_check_mod_optional_2;
+ attribute attr_check_mod_optional_3;
+ attribute attr_check_mod_optional_4;
+ attribute attr_check_mod_optional_5;
+ attribute attr_check_mod_optional_6;
+ attribute attr_check_mod_optional_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ attribute attr_check_mod_optional_disabled_4;
+ attribute attr_check_mod_optional_disabled_7;
+}
+type attr_check_base_2_1_t, attr_check_base_2;
+type attr_check_base_2_2_t;
+typeattribute attr_check_base_2_2_t attr_check_base_2;
+type attr_check_base_3_3_t, attr_check_base_3;
+type attr_check_base_3_4_t;
+typeattribute attr_check_base_3_4_t attr_check_base_3;
+optional {
+ require {
+ attribute attr_check_base_5;
+ }
+ type attr_check_base_5_1_t, attr_check_base_5;
+ type attr_check_base_5_2_t;
+ typeattribute attr_check_base_5_2_t attr_check_base_5;
+}
+optional {
+ require {
+ attribute attr_check_base_6;
+ }
+ type attr_check_base_6_3_t, attr_check_base_6;
+ type attr_check_base_6_4_t;
+ typeattribute attr_check_base_6_4_t attr_check_base_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_8;
+ }
+ type attr_check_base_8_1_t, attr_check_base_8;
+ type attr_check_base_8_2_t;
+ typeattribute attr_check_base_8_2_t attr_check_base_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_9;
+ }
+ type attr_check_base_9_3_t, attr_check_base_9;
+ type attr_check_base_9_4_t;
+ typeattribute attr_check_base_9_4_t attr_check_base_9;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_10;
+ }
+ type attr_check_base_10_3_t, attr_check_base_10;
+ type attr_check_base_10_4_t;
+ typeattribute attr_check_base_10_4_t attr_check_base_10;
+}
+optional {
+ require {
+ attribute attr_check_base_11;
+ }
+ type attr_check_base_11_3_t, attr_check_base_11;
+ type attr_check_base_11_4_t;
+ typeattribute attr_check_base_11_4_t attr_check_base_11;
+}
+type attr_check_base_optional_2_1_t, attr_check_base_optional_2;
+type attr_check_base_optional_2_2_t;
+typeattribute attr_check_base_optional_2_2_t attr_check_base_optional_2;
+optional {
+ require {
+ attribute attr_check_base_optional_5;
+ }
+ type attr_check_base_optional_5_1_t, attr_check_base_optional_5;
+ type attr_check_base_optional_5_2_t;
+ typeattribute attr_check_base_optional_5_2_t attr_check_base_optional_5;
+}
+#optional {
+# require {
+# attribute attr_check_base_optional_6;
+# }
+# type attr_check_base_optional_6_3_t, attr_check_base_optional_6;
+# type attr_check_base_optional_6_4_t;
+# typeattribute attr_check_base_optional_6_4_t attr_check_base_optional_6;
+#}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_optional_8;
+ }
+ type attr_check_base_optional_8_1_t, attr_check_base_optional_8;
+ type attr_check_base_optional_8_2_t;
+ typeattribute attr_check_base_optional_8_2_t attr_check_base_optional_8;
+}
+type attr_check_mod_2_1_t, attr_check_mod_2;
+type attr_check_mod_2_2_t;
+typeattribute attr_check_mod_2_2_t attr_check_mod_2;
+optional {
+ require {
+ attribute attr_check_mod_5;
+ }
+ type attr_check_mod_5_1_t, attr_check_mod_5;
+ type attr_check_mod_5_2_t;
+ typeattribute attr_check_mod_5_2_t attr_check_mod_5;
+}
+optional {
+ require {
+ attribute attr_check_mod_6;
+ }
+ type attr_check_mod_6_3_t, attr_check_mod_6;
+ type attr_check_mod_6_4_t;
+ typeattribute attr_check_mod_6_4_t attr_check_mod_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_8_1_t, attr_check_mod_8;
+ type attr_check_mod_8_2_t;
+ typeattribute attr_check_mod_8_2_t attr_check_mod_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_9_3_t, attr_check_mod_9;
+ type attr_check_mod_9_4_t;
+ typeattribute attr_check_mod_9_4_t attr_check_mod_9;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_10_3_t, attr_check_mod_10;
+ type attr_check_mod_10_4_t;
+ typeattribute attr_check_mod_10_4_t attr_check_mod_10;
+}
+optional {
+ require {
+ type base_t;
+ }
+ type attr_check_mod_11_3_t, attr_check_mod_11;
+ type attr_check_mod_11_4_t;
+ typeattribute attr_check_mod_11_4_t attr_check_mod_11;
+}
+#optional {
+# require {
+# attribute attr_check_mod_optional_5;
+# }
+# type attr_check_mod_optional_5_1_t, attr_check_mod_optional_5;
+# type attr_check_mod_optional_5_2_t;
+# typeattribute attr_check_mod_optional_5_2_t attr_check_mod_optional_5;
+#}
+#optional {
+# require {
+# attribute attr_check_mod_optional_6;
+# }
+# type attr_check_mod_optional_6_3_t, attr_check_mod_optional_6;
+# type attr_check_mod_optional_6_4_t;
+# typeattribute attr_check_mod_optional_6_4_t attr_check_mod_optional_6;
+#}
+optional {
+ require {
+ attribute attr_check_base_optional_disabled_5;
+ }
+ type attr_check_base_optional_disabled_5_1_t, attr_check_base_optional_disabled_5;
+ type attr_check_base_optional_disabled_5_2_t;
+ typeattribute attr_check_base_optional_disabled_5_2_t attr_check_base_optional_disabled_5;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_optional_disabled_8;
+ }
+ type attr_check_base_optional_disabled_8_1_t, attr_check_base_optional_disabled_8;
+ type attr_check_base_optional_disabled_8_2_t;
+ typeattribute attr_check_base_optional_disabled_8_2_t attr_check_base_optional_disabled_8;
+}
+
diff --git a/tests/policies/test-expander/role-base.conf b/tests/policies/test-expander/role-base.conf
new file mode 100644
index 0000000..219987c
--- /dev/null
+++ b/tests/policies/test-expander/role-base.conf
@@ -0,0 +1,479 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+# Role mapping test
+type role_check_1_1_t;
+role role_check_1 types role_check_1_1_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/tests/policies/test-expander/role-module.conf b/tests/policies/test-expander/role-module.conf
new file mode 100644
index 0000000..1cc5d22
--- /dev/null
+++ b/tests/policies/test-expander/role-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require {
+ class file {read write};
+ role role_check_1;
+}
+
+type role_check_1_2_t;
+role role_check_1 types role_check_1_2_t;
diff --git a/tests/policies/test-expander/small-base.conf b/tests/policies/test-expander/small-base.conf
new file mode 100644
index 0000000..6f45a28
--- /dev/null
+++ b/tests/policies/test-expander/small-base.conf
@@ -0,0 +1,718 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+# Type - attribute mapping test
+# Shorthand tests
+# 1 = types in base, 2 = types in mod, 3 = types in both
+# 4 = types in optional in base, 5 = types in optional in mod
+# 6 = types in optional in both
+# 7 = types in disabled optional in base
+# 8 = types in disabled optional in module
+# 9 = types in disabled optional in both
+# 10 = types in enabled optional in base, disabled optional in module
+# 11 = types in disabled optional in base, enabled optional in module
+attribute attr_check_base_1;
+attribute attr_check_base_2;
+attribute attr_check_base_3;
+attribute attr_check_base_4;
+attribute attr_check_base_5;
+attribute attr_check_base_6;
+attribute attr_check_base_7;
+attribute attr_check_base_8;
+attribute attr_check_base_9;
+attribute attr_check_base_10;
+attribute attr_check_base_11;
+optional {
+ require {
+ type module_t;
+ }
+ attribute attr_check_base_optional_1;
+ attribute attr_check_base_optional_2;
+ attribute attr_check_base_optional_3;
+ attribute attr_check_base_optional_4;
+ attribute attr_check_base_optional_5;
+ attribute attr_check_base_optional_6;
+ attribute attr_check_base_optional_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ attribute attr_check_base_optional_disabled_5;
+ attribute attr_check_base_optional_disabled_8;
+}
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+# Type - attribute mapping test
+type base_t;
+type attr_check_base_1_1_t, attr_check_base_1;
+type attr_check_base_1_2_t;
+typeattribute attr_check_base_1_2_t attr_check_base_1;
+type attr_check_base_3_1_t, attr_check_base_3;
+type attr_check_base_3_2_t;
+typeattribute attr_check_base_3_2_t attr_check_base_3;
+optional {
+ require {
+ attribute attr_check_base_4;
+ }
+ type attr_check_base_4_1_t, attr_check_base_4;
+ type attr_check_base_4_2_t;
+ typeattribute attr_check_base_4_2_t attr_check_base_4;
+}
+optional {
+ require {
+ type module_t;
+ }
+ type attr_check_base_6_1_t, attr_check_base_6;
+ type attr_check_base_6_2_t;
+ typeattribute attr_check_base_6_2_t attr_check_base_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_7_1_t, attr_check_base_7;
+ type attr_check_base_7_2_t;
+ typeattribute attr_check_base_7_2_t attr_check_base_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_9_1_t, attr_check_base_9;
+ type attr_check_base_9_2_t;
+ typeattribute attr_check_base_9_2_t attr_check_base_9;
+}
+optional {
+ require {
+ type module_t;
+ }
+ type attr_check_base_10_1_t, attr_check_base_10;
+ type attr_check_base_10_2_t;
+ typeattribute attr_check_base_10_2_t attr_check_base_10;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_11_1_t, attr_check_base_11;
+ type attr_check_base_11_2_t;
+ typeattribute attr_check_base_11_2_t attr_check_base_11;
+}
+#optional {
+# require {
+# attribute attr_check_base_optional_4;
+# }
+# type attr_check_base_optional_4_1_t, attr_check_base_optional_4;
+# type attr_check_base_optional_4_2_t;
+# typeattribute attr_check_base_optional_4_2_t attr_check_base_optional_4;
+#}
+#optional {
+# require {
+# attribute attr_check_base_optional_6;
+# }
+# type attr_check_base_optional_6_1_t, attr_check_base_optional_6;
+# type attr_check_base_optional_6_2_t;
+# typeattribute attr_check_base_optional_6_2_t attr_check_base_optional_6;
+#}
+optional {
+ require {
+ attribute attr_check_mod_4;
+ }
+ type attr_check_mod_4_1_t, attr_check_mod_4;
+ type attr_check_mod_4_2_t;
+ typeattribute attr_check_mod_4_2_t attr_check_mod_4;
+}
+optional {
+ require {
+ attribute attr_check_mod_6;
+ }
+ type attr_check_mod_6_1_t, attr_check_mod_6;
+ type attr_check_mod_6_2_t;
+ typeattribute attr_check_mod_6_2_t attr_check_mod_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_7;
+ }
+ type attr_check_mod_7_1_t, attr_check_mod_7;
+ type attr_check_mod_7_2_t;
+ typeattribute attr_check_mod_7_2_t attr_check_mod_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_9;
+ }
+ type attr_check_mod_9_1_t, attr_check_mod_9;
+ type attr_check_mod_9_2_t;
+ typeattribute attr_check_mod_9_2_t attr_check_mod_9;
+}
+optional {
+ require {
+ attribute attr_check_mod_10;
+ }
+ type attr_check_mod_10_1_t, attr_check_mod_10;
+ type attr_check_mod_10_2_t;
+ typeattribute attr_check_mod_10_2_t attr_check_mod_10;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_11;
+ }
+ type attr_check_mod_11_1_t, attr_check_mod_11;
+ type attr_check_mod_11_2_t;
+ typeattribute attr_check_mod_11_2_t attr_check_mod_11;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_4;
+ }
+ type attr_check_mod_optional_4_1_t, attr_check_mod_optional_4;
+ type attr_check_mod_optional_4_2_t;
+ typeattribute attr_check_mod_optional_4_2_t attr_check_mod_optional_4;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_6;
+ }
+ type attr_check_mod_optional_6_1_t, attr_check_mod_optional_6;
+ type attr_check_mod_optional_6_2_t;
+ typeattribute attr_check_mod_optional_6_2_t attr_check_mod_optional_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_optional_7;
+ }
+ type attr_check_mod_optional_7_1_t, attr_check_mod_optional_7;
+ type attr_check_mod_optional_7_2_t;
+ typeattribute attr_check_mod_optional_7_2_t attr_check_mod_optional_7;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_disabled_4;
+ }
+ type attr_check_mod_optional_disabled_4_1_t, attr_check_mod_optional_disabled_4;
+ type attr_check_mod_optional_disabled_4_2_t;
+ typeattribute attr_check_mod_optional_disabled_4_2_t attr_check_mod_optional_disabled_4;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_optional_disabled_7;
+ }
+ type attr_check_mod_optional_disabled_7_1_t, attr_check_mod_optional_disabled_7;
+ type attr_check_mod_optional_disabled_7_2_t;
+ typeattribute attr_check_mod_optional_disabled_7_2_t attr_check_mod_optional_disabled_7;
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/tests/policies/test-expander/user-base.conf b/tests/policies/test-expander/user-base.conf
new file mode 100644
index 0000000..660152e
--- /dev/null
+++ b/tests/policies/test-expander/user-base.conf
@@ -0,0 +1,482 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+# User mapping test
+type user_check_1_1_t;
+type user_check_1_2_t;
+role user_check_1_1_r types user_check_1_1_t;
+role user_check_1_2_r types user_check_1_2_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(user_check_1,, user_check_1_1_r user_check_1_2_r, s0, s0 - s0:c0.c23)
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/tests/policies/test-expander/user-module.conf b/tests/policies/test-expander/user-module.conf
new file mode 100644
index 0000000..4ef3e62
--- /dev/null
+++ b/tests/policies/test-expander/user-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require {
+ class file {read write};
+ifdef(`enable_mls',`
+ user user_check_1;
+')
+}
+
diff --git a/tests/policies/test-hooks/cmp_policy.conf b/tests/policies/test-hooks/cmp_policy.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/tests/policies/test-hooks/cmp_policy.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+ require {
+ type invalid_type;
+ }
+ allow g_b_role_2 g_b_role_3;
+ role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/tests/policies/test-hooks/module_add_role_allow_trans.conf b/tests/policies/test-hooks/module_add_role_allow_trans.conf
new file mode 100644
index 0000000..c6ecd83
--- /dev/null
+++ b/tests/policies/test-hooks/module_add_role_allow_trans.conf
@@ -0,0 +1,15 @@
+module add_symbol_test 1.0;
+
+require { class file { read }; }
+
+role role_a_1;
+role role_a_2;
+role role_t_1;
+role role_t_2;
+
+type type_rt_1;
+
+
+allow role_a_1 role_a_2;
+
+role_transition role_t_1 type_rt_1 role_t_2;
diff --git a/tests/policies/test-hooks/module_add_symbols.conf b/tests/policies/test-hooks/module_add_symbols.conf
new file mode 100644
index 0000000..cf56e18
--- /dev/null
+++ b/tests/policies/test-hooks/module_add_symbols.conf
@@ -0,0 +1,12 @@
+module add_symbol_test 1.0;
+
+require { class file { read write }; }
+
+type type_add_1;
+attribute attrib_add_1;
+role role_add_1;
+bool bool_add_1 false;
+
+ifdef(`enable_mls',`',`
+user user_add_1 roles { role_add_1 };
+')
diff --git a/tests/policies/test-hooks/small-base.conf b/tests/policies/test-hooks/small-base.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/tests/policies/test-hooks/small-base.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+ require {
+ type invalid_type;
+ }
+ allow g_b_role_2 g_b_role_3;
+ role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/tests/policies/test-linker/module1.conf b/tests/policies/test-linker/module1.conf
new file mode 100644
index 0000000..7cfb6cb
--- /dev/null
+++ b/tests/policies/test-linker/module1.conf
@@ -0,0 +1,138 @@
+module linker_test_1 1.0;
+
+require {
+ class file { read write };
+ class lnk_file append;
+ role g_b_role_2;
+ attribute g_b_attr_3;
+ attribute g_b_attr_5;
+ attribute o4_b_attr_1;
+ type g_b_type_3;
+}
+
+type tag_g_m1;
+
+#test for type in module and attr in module, added to in module
+attribute g_m1_attr_1;
+type g_m1_type_1, g_m1_attr_1;
+type g_m1_type_2;
+typeattribute g_m1_type_2 g_m1_attr_1;
+
+#add role in module test
+role g_m1_role_1 types g_m1_type_1;
+
+# test for attr declared in base, added to in module
+type g_m1_type_3;
+typeattribute g_m1_type_3 g_b_attr_3;
+
+# test for attr declared in base, added to in 2 modules
+type g_m1_type_4;
+typeattribute g_m1_type_4 g_b_attr_5;
+
+# test for attr declared in base optional, added to in module
+type g_m1_type_5;
+typeattribute g_m1_type_5 o4_b_attr_1;
+
+# test for attr declared in module, added to in base optional
+attribute g_m1_attr_2;
+
+#add type to base role test
+role g_b_role_2 types g_m1_type_1;
+role g_b_role_3 types g_m1_type_2;
+
+#add type to base optional role test
+role o1_b_role_2 types g_m1_type_1;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1 types g_m1_type_2;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+attribute g_m1_attr_3;
+type g_m1_type_6, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module , added to in other module optional
+attribute g_m1_attr_4;
+type g_m1_type_7, g_m1_attr_4;
+
+# alias tests
+typealias g_b_type_3 alias g_m_alias_1;
+
+# single boolean in module
+bool g_m1_bool_1 true;
+if (g_m1_bool_1) {
+ allow g_m1_type_1 g_m1_type_2 : lnk_file append;
+}
+
+
+optional {
+ require {
+ type optional_type;
+ attribute g_b_attr_4;
+ attribute o1_b_attr_2;
+ class lnk_file { ioctl };
+ }
+
+ type tag_o1_m1;
+
+ attribute o1_m1_attr_1;
+ type o1_m1_type_2, o1_m1_attr_1;
+
+ type o1_m1_type_1;
+ role o1_m1_role_1 types o1_m1_type_1;
+
+ type o1_m1_type_3;
+ typeattribute o1_m1_type_3 g_b_attr_4;
+
+ type o1_m1_type_5;
+ typeattribute o1_m1_type_5 o1_b_attr_2;
+
+ bool o1_m1_bool_1 false;
+ if (o1_m1_bool_1) {
+ allow o1_m1_type_2 o1_m1_type_1 : lnk_file ioctl;
+ }
+
+}
+
+optional {
+ require {
+ type optional_type;
+ #role g_b_role_4; // This causes a bug where the role scope doesn't get copied into base
+ }
+
+ type tag_o2_m1;
+
+ role g_b_role_4 types g_m1_type_2;
+}
+
+optional {
+ require {
+ attribute g_b_attr_6;
+ }
+
+ type tag_o3_m1;
+
+ type o3_m1_type_1;
+ role o3_b_role_1 types o3_m1_type_1;
+
+ type o3_m1_type_2, g_b_attr_6;
+
+ attribute o3_m1_attr_1;
+
+ # attr a added to in base optional, declared/added in module optional, added to in other module
+ attribute o3_m1_attr_2;
+ type o3_m1_type_3, o3_m1_attr_2;
+
+}
+
+optional {
+ require {
+ type enable_optional;
+ }
+ type tag_o4_m1;
+
+ attribute o4_m1_attr_1;
+ type o4_m1_type_1;
+ typeattribute o4_m1_type_1 o4_m1_attr_1;
+
+
+}
diff --git a/tests/policies/test-linker/module2.conf b/tests/policies/test-linker/module2.conf
new file mode 100644
index 0000000..3820cb7
--- /dev/null
+++ b/tests/policies/test-linker/module2.conf
@@ -0,0 +1,62 @@
+module linker_test_2 1.0;
+
+require {
+ class file { read write };
+ class lnk_file { unlink };
+ attribute g_b_attr_5;
+ attribute g_b_attr_6;
+ attribute g_m1_attr_3;
+ attribute o3_m1_attr_2;
+}
+
+type tag_g_m2;
+
+type g_m2_type_1;
+role g_m2_role_1 types g_m2_type_1;
+
+type g_m2_type_4, g_b_attr_5;
+type g_m2_type_5, g_b_attr_6;
+
+#add types to role declared in base test
+type g_m2_type_2;
+role g_b_role_3 types g_m2_type_2;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1 types g_m2_type_1;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+type g_m2_type_3, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module optional, added to in other module
+type g_m2_type_6, o3_m1_attr_2;
+
+# cond mapping tests
+bool g_m2_bool_1 true;
+bool g_m2_bool_2 false;
+if (g_m2_bool_1 && g_m2_bool_2) {
+ allow g_m2_type_1 g_m2_type_2 : lnk_file unlink;
+}
+
+optional {
+ require {
+ type optional_type;
+ }
+
+ type tag_o1_m2;
+
+ type o1_m2_type_1;
+ role o1_m2_role_1 types o1_m2_type_1;
+}
+
+
+optional {
+ require {
+ attribute g_m1_attr_4;
+ attribute o4_m1_attr_1;
+ }
+ type tag_o2_m2;
+
+ type o2_m2_type_1, g_m1_attr_4;
+ type o2_m2_type_2, o4_m1_attr_1;
+
+}
diff --git a/tests/policies/test-linker/small-base.conf b/tests/policies/test-linker/small-base.conf
new file mode 100644
index 0000000..2f166c9
--- /dev/null
+++ b/tests/policies/test-linker/small-base.conf
@@ -0,0 +1,593 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type enable_optional;
+
+#decorative type for finding this decl, every block should have one
+type tag_g_b;
+
+attribute g_b_attr_1;
+attribute g_b_attr_2;
+attribute g_b_attr_3;
+attribute g_b_attr_4;
+attribute g_b_attr_5;
+attribute g_b_attr_6;
+
+type g_b_type_1, g_b_attr_1;
+type g_b_type_2, g_b_attr_2;
+type g_b_type_3;
+
+role g_b_role_1 types g_b_type_1;
+role g_b_role_2 types g_b_type_2;
+role g_b_role_3 types g_b_type_2;
+role g_b_role_4 types g_b_type_2;
+
+bool g_b_bool_1 false;
+bool g_b_bool_2 true;
+
+allow g_b_type_1 g_b_type_2 : security { compute_av load_policy };
+allow g_b_type_1 g_b_type_2 : file *; # test *
+allow g_b_type_1 g_b_type_2 : process ~ptrace; #test ~
+
+typealias g_b_type_3 alias g_b_alias_1;
+
+if (g_b_bool_1) {
+ allow g_b_type_1 g_b_type_2: lnk_file read;
+}
+
+
+optional {
+ require {
+ type enable_optional;
+ attribute g_m1_attr_2;
+ }
+ type tag_o1_b;
+
+ attribute o1_b_attr_1;
+ type o1_b_type_1, o1_b_attr_1;
+ bool o1_b_bool_1 true;
+ role o1_b_role_1 types o1_b_type_1;
+
+ role o1_b_role_2 types o1_b_type_1;
+
+ attribute o1_b_attr_2;
+
+ type o1_b_type_2, g_m1_attr_2;
+
+ if (o1_b_bool_1) {
+ allow o1_b_type_1 o1_b_type_2: lnk_file write;
+ }
+
+}
+
+optional {
+ require {
+ # this should be activated by module 1
+ type g_m1_type_1;
+ attribute o3_m1_attr_2;
+ }
+ type tag_o2_b;
+
+ type o2_b_type_1, o3_m1_attr_2;
+}
+
+optional {
+ require {
+ #this block should not come on
+ type invalid_type;
+ }
+ type tag_o3_b;
+
+
+ attribute o3_b_attr_1;
+ type o3_b_type_1;
+ bool o3_b_bool_1 true;
+
+ role o3_b_role_1 types o3_b_type_1;
+
+ allow g_b_type_1 invalid_type : sem { create destroy };
+}
+
+optional {
+ require {
+ # also should be enabled by module 1
+ type enable_optional;
+ type g_m1_type_1;
+ attribute o3_m1_attr_1;
+ attribute g_m1_attr_3;
+ }
+
+ type tag_o4_b;
+
+ attribute o4_b_attr_1;
+
+ role o4_b_role_1 types g_m1_type_1;
+
+ # test for attr declared in module optional, added to in base optional
+ type o4_b_type_1, o3_m1_attr_1;
+
+ type o4_b_type_2, g_m1_attr_3;
+}
+
+optional {
+ require {
+ attribute g_m1_attr_4;
+ attribute o4_m1_attr_1;
+ }
+ type tag_o5_b;
+
+ type o5_b_type_1, g_m1_attr_4;
+ type o5_b_type_2, o4_m1_attr_1;
+}
+
+optional {
+ require {
+ type enable_optional;
+ }
+ type tag_o6_b;
+
+ typealias g_b_type_3 alias g_b_alias_2;
+}
+
+optional {
+ require {
+ type g_m_alias_1;
+ }
+ type tag_o7_b;
+
+ allow g_m_alias_1 enable_optional:file read;
+}
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+gen_user(g_b_user_2,, g_b_role_1, s0, s0 - s0:c0, c1, c3, c4, c5)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/tests/test-common.c b/tests/test-common.c
new file mode 100644
index 0000000..058b743
--- /dev/null
+++ b/tests/test-common.c
@@ -0,0 +1,262 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This has tests that are common between test suites*/
+
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len)
+{
+ scope_datum_t *scope;
+ int found;
+ unsigned int i, j;
+ /* make sure it is in global symtab */
+ if (!hashtab_search(p->symtab[sym_type].table, id)) {
+ fprintf(stderr, "symbol %s not found in table %d\n", id, sym_type);
+ CU_FAIL_FATAL();
+ }
+ /* make sure its scope is correct */
+ scope = hashtab_search(p->scope[sym_type].table, id);
+ CU_ASSERT_FATAL(scope != NULL);
+ CU_ASSERT(scope->scope == scope_type);
+ CU_ASSERT(scope->decl_ids_len == len);
+ if (scope->decl_ids_len != len)
+ fprintf(stderr, "sym %s has %d decls, %d expected\n", id, scope->decl_ids_len, len);
+ for (i = 0; i < len; i++) {
+ found = 0;
+ for (j = 0; j < len; j++) {
+ if (decls[i] == scope->decl_ids[j])
+ found++;
+ }
+ CU_ASSERT(found == 1);
+ }
+
+}
+
+static int common_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ common_datum_t *d = (common_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_COMMONS][d->s.value - 1] == (char *)key);
+ return 0;
+}
+
+static int class_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ class_datum_t *d = (class_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_CLASSES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->class_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int role_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ role_datum_t *d = (role_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_ROLES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->role_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int type_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ type_datum_t *d = (type_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ if (!d->primary)
+ return 0;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_TYPES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->type_val_to_struct[d->s.value - 1] == d);
+
+ return 0;
+}
+
+static int user_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ user_datum_t *d = (user_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_USERS][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->user_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int cond_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ cond_bool_datum_t *d = (cond_bool_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_BOOLS][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->bool_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int level_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ level_datum_t *d = (level_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_LEVELS][d->level->sens - 1] == (char *)key);
+ return 0;
+}
+
+static int cat_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ cat_datum_t *d = (cat_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_CATS][d->s.value - 1] == (char *)key);
+ return 0;
+}
+
+static int (*test_index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *p) = {
+common_test_index, class_test_index, role_test_index, type_test_index, user_test_index, cond_test_index, level_test_index, cat_test_index,};
+
+void test_policydb_indexes(policydb_t * p)
+{
+ int i;
+
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_map(p->symtab[i].table, test_index_f[i], p);
+ }
+}
+
+void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor)
+{
+ type_datum_t *type, *primary;
+ unsigned int my_primary, my_flavor, my_value;
+
+ type = hashtab_search(p->p_types.table, id);
+ primary = hashtab_search(p->p_types.table, primary_id);
+
+ CU_ASSERT_PTR_NOT_NULL(type);
+ CU_ASSERT_PTR_NOT_NULL(primary);
+
+ if (type && primary) {
+ if (mode) {
+ my_flavor = type->flavor;
+ } else {
+ my_flavor = flavor;
+ }
+
+ if (my_flavor == TYPE_TYPE) {
+ my_primary = 0;
+ my_value = primary->s.value;
+ } else if (my_flavor == TYPE_ALIAS) {
+ my_primary = primary->s.value;
+ CU_ASSERT_NOT_EQUAL(type->s.value, primary->s.value);
+ my_value = type->s.value;
+ } else {
+ CU_FAIL("not an alias");
+ }
+
+ CU_ASSERT(type->primary == my_primary);
+ CU_ASSERT(type->flavor == my_flavor);
+ CU_ASSERT(type->s.value == my_value);
+ }
+}
+
+role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags)
+{
+ ebitmap_node_t *tnode;
+ unsigned int i, j, new, found = 0;
+ role_datum_t *role;
+
+ if (decl)
+ role = hashtab_search(decl->p_roles.table, id);
+ else
+ role = hashtab_search(p->p_roles.table, id);
+
+ if (!role)
+ printf("role %s can't be found! \n", id);
+
+ CU_ASSERT_FATAL(role != NULL);
+
+ ebitmap_for_each_bit(&role->types.types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ new = 0;
+ for (j = 0; j < len; j++) {
+ if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+ found++;
+ new = 1;
+ }
+ }
+ if (new == 0) {
+ printf("\nRole %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+ }
+ CU_ASSERT(new == 1);
+ }
+ }
+ CU_ASSERT(found == len);
+ if (found != len)
+ printf("\nrole %s has %d types, %d expected\n", p->sym_val_to_name[SYM_ROLES][role->s.value - 1], found, len);
+ /* roles should never have anything in the negset */
+ CU_ASSERT(role->types.negset.highbit == 0);
+ CU_ASSERT(role->types.flags == flags);
+
+ return role;
+}
+
+void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len)
+{
+ ebitmap_node_t *tnode;
+ int j, new, found = 0;
+ unsigned int i;
+ type_datum_t *attr;
+
+ if (decl)
+ attr = hashtab_search(decl->p_types.table, id);
+ else
+ attr = hashtab_search(p->p_types.table, id);
+
+ if (attr == NULL)
+ printf("could not find attr %s in decl %d\n", id, decl->decl_id);
+ CU_ASSERT_FATAL(attr != NULL);
+ CU_ASSERT(attr->flavor == TYPE_ATTRIB);
+ CU_ASSERT(attr->primary == 1);
+
+ ebitmap_for_each_bit(&attr->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ new = 0;
+ for (j = 0; j < len; j++) {
+ if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+ found++;
+ new = 1;
+ }
+ }
+ if (new == 0) {
+ printf("\nattr %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+ }
+ CU_ASSERT(new == 1);
+ }
+ }
+ CU_ASSERT(found == len);
+ if (found != len)
+ printf("\nattr %s has %d types, %d expected\n", id, found, len);
+}
diff --git a/tests/test-common.h b/tests/test-common.h
new file mode 100644
index 0000000..5a1e650
--- /dev/null
+++ b/tests/test-common.h
@@ -0,0 +1,78 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_COMMON_H__
+#define __TEST_COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+
+/* p the policy being inspected
+ * id string symbol identifier
+ * sym_type symbol type (eg., SYM_ROLES, SYM_TYPES)
+ * scope_type what scope the role should have (eg., SCOPE_DECL or SCOPE_REQ)
+ * decls integer array of decl id's that we expect the role to have in the scope table
+ * len number of elements in decls
+ *
+ * This is a utility function to test for the symbol's presence in the global symbol table,
+ * the scope table, and that the decl blocks we think this symbol is in are correct
+ */
+extern void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len);
+
+/* Test the indexes in the policydb to ensure their correctness. These include
+ * the sym_val_to_name[], class_val_to_struct, role_val_to_struct, type_val_to_struct,
+ * user_val_to_struct, and bool_val_to_struct indexes.
+ */
+extern void test_policydb_indexes(policydb_t * p);
+
+/* Test alias datum to ensure that it is as expected
+ *
+ * id = the key for the alias
+ * primary_id = the key for its primary
+ * mode: 0 = test the datum according to the flavor value in the call
+ 1 = automatically detect the flavor value and test the datum accordingly
+ * flavor = flavor value if in mode 0
+ */
+extern void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor);
+
+/* p the policy being inspected
+ * id string role identifier
+ * decl the decl block which we are looking in for the role datum
+ * types the array of string types which we expect the role has in its type ebitmap
+ * len number of elements in types
+ * flags the expected flags in the role typeset (eg., * or ~)
+ *
+ * This is a utility function to test whether the type set associated with a role in a specific
+ * avrule decl block matches our expectations
+ */
+extern role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags);
+
+/* p the policy being inspected
+ * id string attribute identifier
+ * decl the decl block which we are looking in for the attribute datum
+ * types the array of string types which we expect the attribute has in its type ebitmap
+ * len number of elements in types
+ *
+ * This is a utility function to test whether the type set associated with an attribute in a specific
+ * avrule decl block matches our expectations
+ */
+extern void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len);
+
+#endif
diff --git a/tests/test-cond.c b/tests/test-cond.c
new file mode 100644
index 0000000..32bf6f1
--- /dev/null
+++ b/tests/test-cond.c
@@ -0,0 +1,95 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-cond.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+
+static policydb_t basemod;
+static policydb_t base_expanded;
+
+int cond_test_init(void)
+{
+ if (policydb_init(&base_expanded)) {
+ fprintf(stderr, "out of memory!\n");
+ policydb_destroy(&basemod);
+ return -1;
+ }
+
+ if (test_load_policy(&basemod, POLICY_BASE, 1, "test-cond", "refpolicy-base.conf"))
+ goto cleanup;
+
+ if (link_modules(NULL, &basemod, NULL, 0, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ goto cleanup;
+ }
+
+ if (expand_module(NULL, &basemod, &base_expanded, 0, 1)) {
+ fprintf(stderr, "expand module failed\n");
+ goto cleanup;
+ }
+
+ return 0;
+
+ cleanup:
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+ return -1;
+}
+
+int cond_test_cleanup(void)
+{
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+
+ return 0;
+}
+
+static void test_cond_expr_equal(void)
+{
+ cond_node_t *a, *b;
+
+ a = base_expanded.cond_list;
+ while (a) {
+ b = base_expanded.cond_list;
+ while (b) {
+ if (a == b) {
+ CU_ASSERT(cond_expr_equal(a, b));
+ } else {
+ CU_ASSERT(cond_expr_equal(a, b) == 0);
+ }
+ b = b->next;
+ }
+ a = a->next;
+ }
+}
+
+int cond_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "cond_expr_equal", test_cond_expr_equal)) {
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/tests/test-cond.h b/tests/test-cond.h
new file mode 100644
index 0000000..702d9e0
--- /dev/null
+++ b/tests/test-cond.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_COND_H__
+#define __TEST_COND_H__
+
+#include <CUnit/Basic.h>
+
+int cond_test_init(void);
+int cond_test_cleanup(void);
+int cond_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/tests/test-deps.c b/tests/test-deps.c
new file mode 100644
index 0000000..e7d2beb
--- /dev/null
+++ b/tests/test-deps.c
@@ -0,0 +1,302 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-deps.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <stdlib.h>
+
+/* Tests for dependency checking / handling, specifically:
+ *
+ * 1 type in module global.
+ * 2 attribute in module global.
+ * 3 object class / perm in module global.
+ * 4 boolean in module global.
+ * 5 role in module global.
+ *
+ * 6 type in module optional.
+ * 7 attribute in module optional.
+ * 8 object class / perm in module optional.
+ * 9 boolean in module optional.
+ * 10 role in module optional.
+ *
+ * 11 type in base optional.
+ * 12 attribute in base optional.
+ * 13 object class / perm in base optional.
+ * 14 boolean in base optional.
+ * 15 role in base optional.
+ *
+ * Each of these tests are done with the dependency met and not
+ * met. Additionally, each of the required symbols is used in the
+ * scope it is required.
+ *
+ * In addition to the simple tests, we have test with more complex
+ * modules that test:
+ *
+ * 17 mutual dependencies between two modules.
+ * 18 circular dependency between three modules.
+ * 19 large number of dependencies in a module with a more complex base.
+ * 20 nested optionals with requires.
+ *
+ * Again, each of these tests is done with the requirements met and not
+ * met.
+ */
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+
+#define BASE_MODREQ_TYPE_GLOBAL 0
+#define BASE_MODREQ_ATTR_GLOBAL 1
+#define BASE_MODREQ_OBJ_GLOBAL 2
+#define BASE_MODREQ_BOOL_GLOBAL 3
+#define BASE_MODREQ_ROLE_GLOBAL 4
+#define BASE_MODREQ_PERM_GLOBAL 5
+#define BASE_MODREQ_TYPE_OPT 6
+#define BASE_MODREQ_ATTR_OPT 7
+#define BASE_MODREQ_OBJ_OPT 8
+#define BASE_MODREQ_BOOL_OPT 9
+#define BASE_MODREQ_ROLE_OPT 10
+#define BASE_MODREQ_PERM_OPT 11
+#define NUM_BASES 12
+
+static policydb_t bases_met[NUM_BASES];
+static policydb_t bases_notmet[NUM_BASES];
+
+extern int mls;
+
+int deps_test_init(void)
+{
+ int i;
+
+ /* To test linking we need 1 base per link test and in
+ * order to load them in the init function we have
+ * to keep them all around. Not ideal, but it shouldn't
+ * matter too much.
+ */
+ for (i = 0; i < NUM_BASES; i++) {
+ if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
+ return -1;
+ }
+
+ for (i = 0; i < NUM_BASES; i++) {
+ if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
+ return -1;
+ }
+
+ return 0;
+}
+
+int deps_test_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_BASES; i++) {
+ policydb_destroy(&bases_met[i]);
+ }
+
+ for (i = 0; i < NUM_BASES; i++) {
+ policydb_destroy(&bases_notmet[i]);
+ }
+
+ return 0;
+}
+
+/* This function performs testing of the dependency handles for module global
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ * req_met boolean indicating whether the base policy meets the
+ * requirements for the modules global block.
+ * b index of the base policy in the global bases_met array.
+ *
+ * policy name of the policy module to load for this test.
+ * decl_type name of the unique type found in the module's global
+ * section is to find that avrule_decl.
+ */
+static void do_deps_modreq_global(int req_met, int b, char *policy, char *decl_type)
+{
+ policydb_t *base;
+ policydb_t mod;
+ policydb_t *mods[] = { &mod };
+ avrule_decl_t *decl;
+ int ret, link_ret;
+ sepol_handle_t *h;
+
+ /* suppress error reporting - this is because we know that we
+ * are going to get errors and don't want libsepol complaining
+ * about it constantly. */
+ h = sepol_handle_create();
+ CU_ASSERT_FATAL(h != NULL);
+ sepol_msg_set_callback(h, NULL, NULL);
+
+ if (req_met) {
+ base = &bases_met[b];
+ link_ret = 0;
+ } else {
+ base = &bases_notmet[b];
+ link_ret = -3;
+ }
+
+ CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+ /* link the modules and check for the correct return value.
+ */
+ ret = link_modules(h, base, mods, 1, 0);
+ CU_ASSERT_FATAL(ret == link_ret);
+ policydb_destroy(&mod);
+
+ if (!req_met)
+ return;
+
+ decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+ CU_ASSERT_FATAL(decl != NULL);
+
+ CU_ASSERT(decl->enabled == 1);
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 1 - 5 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_global(void)
+{
+ /* object classes */
+ do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+ /* types */
+ do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+ /* attributes */
+ do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+ /* booleans */
+ do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+ /* roles */
+ do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+ do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+}
+
+/* This function performs testing of the dependency handles for module optional
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ * req_met boolean indicating whether the base policy meets the
+ * requirements for the modules global block.
+ * b index of the base policy in the global bases_met array.
+ *
+ * policy name of the policy module to load for this test.
+ * decl_type name of the unique type found in the module's global
+ * section is to find that avrule_decl.
+ */
+static void do_deps_modreq_opt(int req_met, int ret_val, int b, char *policy, char *decl_type)
+{
+ policydb_t *base;
+ policydb_t mod;
+ policydb_t *mods[] = { &mod };
+ avrule_decl_t *decl;
+ int ret;
+ sepol_handle_t *h;
+
+ /* suppress error reporting - this is because we know that we
+ * are going to get errors and don't want libsepol complaining
+ * about it constantly. */
+ h = sepol_handle_create();
+ CU_ASSERT_FATAL(h != NULL);
+ sepol_msg_set_callback(h, NULL, NULL);
+
+ if (req_met) {
+ base = &bases_met[b];
+ } else {
+ base = &bases_notmet[b];
+ }
+
+ CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+ /* link the modules and check for the correct return value.
+ */
+ ret = link_modules(h, base, mods, 1, 0);
+ CU_ASSERT_FATAL(ret == ret_val);
+ policydb_destroy(&mod);
+ if (ret_val < 0)
+ return;
+
+ decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+ CU_ASSERT_FATAL(decl != NULL);
+
+ if (req_met) {
+ CU_ASSERT(decl->enabled == 1);
+ } else {
+ CU_ASSERT(decl->enabled == 0);
+ }
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 6 - 10 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_opt(void)
+{
+ /* object classes */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+ /* types */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+ /* attributes */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+ /* booleans */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+ /* roles */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+ /* permissions */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+}
+
+int deps_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
+ return CU_get_error();
+ }
+
+ return 0;
+}
diff --git a/tests/test-deps.h b/tests/test-deps.h
new file mode 100644
index 0000000..fbd2ace
--- /dev/null
+++ b/tests/test-deps.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_DEPS_H__
+#define __TEST_DEPS_H__
+
+#include <CUnit/Basic.h>
+
+int deps_test_init(void);
+int deps_test_cleanup(void);
+int deps_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/tests/test-downgrade.c b/tests/test-downgrade.c
new file mode 100644
index 0000000..1ee7ff4
--- /dev/null
+++ b/tests/test-downgrade.c
@@ -0,0 +1,273 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-downgrade.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <CUnit/Basic.h>
+
+#define POLICY_BIN_HI "policies/test-downgrade/policy.hi"
+#define POLICY_BIN_LO "policies/test-downgrade/policy.lo"
+
+static policydb_t policydb;
+
+/*
+ * Function Name: downgrade_test_init
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void)
+{
+ /* Initialize the policydb_t structure */
+ if (policydb_init(&policydb)) {
+ fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function Name: downgrade_test_cleanup
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void)
+{
+ policydb_destroy(&policydb);
+
+ return 0;
+}
+
+/*
+ * Function Name: downgrade_add_tests
+ *
+ * Input: CU_pSuite
+ *
+ * Output: Returns 0 upon success. Returns a CUnit error value on failure.
+ *
+ * Description: Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite)
+{
+ if (CU_add_test(suite, "downgrade", test_downgrade) == NULL)
+ return CU_get_error();
+
+ return 0;
+}
+
+/*
+ * Function Name: test_downgrade_possible
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description:
+ * Tests the backward compatability of MLS and Non-MLS binary policy versions.
+ */
+void test_downgrade(void)
+{
+ if (do_downgrade_test(0) < 0)
+ fprintf(stderr,
+ "\nError during downgrade testing of Non-MLS policy\n");
+
+
+ if (do_downgrade_test(1) < 0)
+ fprintf(stderr,
+ "\nError during downgrade testing of MLS policy\n");
+}
+
+/*
+ * Function Name: do_downgrade_test
+ *
+ * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing
+ *
+ * Output: 0 on success, negative number upon failure
+ *
+ * Description: This function handles the downgrade testing.
+ * A binary policy is read into the policydb structure, the
+ * policy version is decreased by a specific amount, written
+ * back out and then read back in again. The process is
+ * repeated until the minimum policy version is reached.
+ */
+int do_downgrade_test(int mls)
+{
+ policydb_t policydb_tmp;
+ int hi, lo, version;
+
+ /* Reset policydb for re-use */
+ policydb_destroy(&policydb);
+ downgrade_test_init();
+
+ /* Read in the hi policy from file */
+ if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) {
+ fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : "");
+ CU_FAIL("Unable to read the binary policy");
+ return -1;
+ }
+
+ /* Change MLS value based on parameter */
+ policydb.mls = mls ? 1 : 0;
+
+ for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) {
+ /* Stash old version number */
+ version = policydb.policyvers;
+
+ /* Try downgrading to each possible version. */
+ for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) {
+
+ /* Reduce policy version */
+ policydb.policyvers = lo;
+
+ /* Write out modified binary policy */
+ if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) {
+ /*
+ * Error from MLS to pre-MLS is expected due
+ * to MLS re-implementation in version 19.
+ */
+ if (mls && lo < POLICYDB_VERSION_MLS)
+ continue;
+
+ fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+ CU_FAIL("Failed to write downgraded binary policy");
+ return -1;
+ }
+
+ /* Make sure we can read back what we wrote. */
+ if (policydb_init(&policydb_tmp)) {
+ fprintf(stderr, "%s: Out of memory!\n",
+ __FUNCTION__);
+ return -1;
+ }
+ if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) {
+ fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+ CU_FAIL("Unable to read downgraded binary policy");
+ return -1;
+ }
+ policydb_destroy(&policydb_tmp);
+ }
+ /* Restore version number */
+ policydb.policyvers = version;
+ }
+
+ return 0;
+}
+
+/*
+ * Function Name: read_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read binary policy into policydb
+ * structure.
+ */
+int read_binary_policy(const char *path, policydb_t *p)
+{
+ FILE *in_fp = NULL;
+ struct policy_file f;
+ int rc;
+
+ /* Open the binary policy file */
+ if ((in_fp = fopen(path, "rb")) == NULL) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ sepol_handle_destroy(f.handle);
+ return -1;
+ }
+
+ /* Read in the binary policy. */
+ memset(&f, 0, sizeof(struct policy_file));
+ f.type = PF_USE_STDIO;
+ f.fp = in_fp;
+ rc = policydb_read(p, &f, 0);
+
+ sepol_handle_destroy(f.handle);
+ fclose(in_fp);
+ return rc;
+}
+
+/*
+ * Function Name: write_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: open file and write the binary policy from policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *p)
+{
+ FILE *out_fp = NULL;
+ struct policy_file f;
+ sepol_handle_t *handle;
+ int rc;
+
+ /* We don't want libsepol to print warnings to stderr */
+ handle = sepol_handle_create();
+ if (handle == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return -1;
+ }
+ sepol_msg_set_callback(handle, NULL, NULL);
+
+ /* Open the binary policy file for writing */
+ if ((out_fp = fopen(path, "w" )) == NULL) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ sepol_handle_destroy(f.handle);
+ return -1;
+ }
+
+ /* Write the binary policy */
+ memset(&f, 0, sizeof(struct policy_file));
+ f.type = PF_USE_STDIO;
+ f.fp = out_fp;
+ f.handle = handle;
+ rc = policydb_write(p, &f);
+
+ sepol_handle_destroy(f.handle);
+ fclose(out_fp);
+ return rc;
+}
diff --git a/tests/test-downgrade.h b/tests/test-downgrade.h
new file mode 100644
index 0000000..10a7c3b
--- /dev/null
+++ b/tests/test-downgrade.h
@@ -0,0 +1,119 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_DOWNGRADE_H__
+#define __TEST_DOWNGRADE_H__
+
+#include <CUnit/Basic.h>
+#include <sepol/policydb/policydb.h>
+
+/*
+ * Function Name: downgrade_test_init
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void);
+
+/*
+ * Function Name: downgrade_test_cleanup
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void);
+
+/*
+ * Function Name: downgrade_add_tests
+ *
+ * Input: CU_pSuite
+ *
+ * Output: Returns 0 upon success. Upon failure, a CUnit testing error
+ * value is returned
+ *
+ * Description: Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite);
+
+/*
+ * Function Name: test_downgrade_possible
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Tests the backward compatability of MLS and Non-MLS binary
+ * policy versions.
+ */
+void test_downgrade(void);
+
+/*
+ * Function Name: do_downgrade_test
+ *
+ * Input: int that represents a 0 for Non-MLS policy and a
+ * 1 for MLS policy downgrade testing
+ *
+ * Output: (int) 0 on success, negative number upon failure
+ *
+ * Description: This function handles the downgrade testing. A binary policy
+ * is read into the policydb structure, the policy version is
+ * decreased by a specific amount, written back out and then read
+ * back in again. The process is iterative until the minimum
+ * policy version is reached.
+ */
+int do_downgrade_test(int mls);
+
+/*
+ * Function Name: read_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read in the binary policy
+ * into the policydb structure.
+ */
+int read_binary_policy(const char *path, policydb_t *);
+
+/*
+ * Function Name: write_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read in the binary policy
+ * into the policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *);
+
+#endif
diff --git a/tests/test-expander-attr-map.c b/tests/test-expander-attr-map.c
new file mode 100644
index 0000000..5c24ced
--- /dev/null
+++ b/tests/test-expander-attr-map.c
@@ -0,0 +1,105 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-attr-map.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t base_expanded2;
+
+void test_expander_attr_mapping(void)
+{
+ /* note that many cases are ommitted because they don't make sense
+ (i.e. declaring in an optional and then using it in the base) or
+ because declare in optional then require in a different optional
+ logic still doesn't work */
+
+ char *typesb1[] = { "attr_check_base_1_1_t", "attr_check_base_1_2_t" };
+ char *typesb2[] = { "attr_check_base_2_1_t", "attr_check_base_2_2_t" };
+ char *typesb3[] = { "attr_check_base_3_1_t", "attr_check_base_3_2_t",
+ "attr_check_base_3_3_t", "attr_check_base_3_4_t"
+ };
+ char *typesb4[] = { "attr_check_base_4_1_t", "attr_check_base_4_2_t" };
+ char *typesb5[] = { "attr_check_base_5_1_t", "attr_check_base_5_2_t" };
+ char *typesb6[] = { "attr_check_base_6_1_t", "attr_check_base_6_2_t",
+ "attr_check_base_6_3_t", "attr_check_base_6_4_t"
+ };
+ char *typesbo2[] = { "attr_check_base_optional_2_1_t",
+ "attr_check_base_optional_2_2_t"
+ };
+ char *typesbo5[] = { "attr_check_base_optional_5_1_t",
+ "attr_check_base_optional_5_2_t"
+ };
+ char *typesm2[] = { "attr_check_mod_2_1_t", "attr_check_mod_2_2_t" };
+ char *typesm4[] = { "attr_check_mod_4_1_t", "attr_check_mod_4_2_t" };
+ char *typesm5[] = { "attr_check_mod_5_1_t", "attr_check_mod_5_2_t" };
+ char *typesm6[] = { "attr_check_mod_6_1_t", "attr_check_mod_6_2_t",
+ "attr_check_mod_6_3_t", "attr_check_mod_6_4_t"
+ };
+ char *typesmo2[] = { "attr_check_mod_optional_4_1_t",
+ "attr_check_mod_optional_4_2_t"
+ };
+ char *typesb10[] = { "attr_check_base_10_1_t", "attr_check_base_10_2_t" };
+ char *typesb11[] = { "attr_check_base_11_3_t", "attr_check_base_11_4_t" };
+ char *typesm10[] = { "attr_check_mod_10_1_t", "attr_check_mod_10_2_t" };
+ char *typesm11[] = { "attr_check_mod_11_3_t", "attr_check_mod_11_4_t" };
+
+ test_attr_types(&base_expanded2, "attr_check_base_1", NULL, typesb1, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_2", NULL, typesb2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_3", NULL, typesb3, 4);
+ test_attr_types(&base_expanded2, "attr_check_base_4", NULL, typesb4, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_5", NULL, typesb5, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_6", NULL, typesb6, 4);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_2", NULL, typesbo2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_5", NULL, typesbo5, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_2", NULL, typesm2, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_4", NULL, typesm4, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_5", NULL, typesm5, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_6", NULL, typesm6, 4);
+ test_attr_types(&base_expanded2, "attr_check_mod_optional_4", NULL, typesmo2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_7", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_9", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_10", NULL, typesb10, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_11", NULL, typesb11, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_7", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_9", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_10", NULL, typesm10, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_11", NULL, typesm11, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_optional_7", NULL, NULL, 0);
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_2_t"));
+}
diff --git a/tests/test-expander-attr-map.h b/tests/test-expander-attr-map.h
new file mode 100644
index 0000000..6a10089
--- /dev/null
+++ b/tests/test-expander-attr-map.h
@@ -0,0 +1,26 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER__ATTR_MAP_H__
+#define __TEST_EXPANDER__ATTR_MAP_H__
+
+void test_expander_attr_mapping(void);
+
+#endif
diff --git a/tests/test-expander-roles.c b/tests/test-expander-roles.c
new file mode 100644
index 0000000..ecfa88e
--- /dev/null
+++ b/tests/test-expander-roles.c
@@ -0,0 +1,37 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-roles.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t role_expanded;
+
+void test_expander_role_mapping(void)
+{
+ char *types1[] = { "role_check_1_1_t", "role_check_1_2_t" };
+
+ test_role_type_set(&role_expanded, "role_check_1", NULL, types1, 2, 0);
+}
diff --git a/tests/test-expander-roles.h b/tests/test-expander-roles.h
new file mode 100644
index 0000000..380d2ef
--- /dev/null
+++ b/tests/test-expander-roles.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_ROLE_H__
+#define __TEST_EXPANDER_ROLE_H__
+
+void test_expander_role_mapping(void);
+
+#endif
diff --git a/tests/test-expander-users.c b/tests/test-expander-users.c
new file mode 100644
index 0000000..549492b
--- /dev/null
+++ b/tests/test-expander-users.c
@@ -0,0 +1,75 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-users.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t user_expanded;
+
+static void check_user_roles(policydb_t * p, char *user_name, char **role_names, int num_roles)
+{
+ user_datum_t *user;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ int j;
+ unsigned char *found; /* array of booleans of roles found */
+ int extra = 0; /* number of extra roles found */
+
+ user = (user_datum_t *) hashtab_search(p->p_users.table, user_name);
+ if (!user) {
+ printf("%s not found\n", user_name);
+ CU_FAIL("user not found");
+ return;
+ }
+ found = calloc(num_roles, sizeof(unsigned char));
+ CU_ASSERT_FATAL(found != NULL);
+ ebitmap_for_each_bit(&user->roles.roles, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ extra++;
+ for (j = 0; j < num_roles; j++) {
+ if (strcmp(role_names[j], p->p_role_val_to_name[i]) == 0) {
+ extra--;
+ found[j] += 1;
+ break;
+ }
+ }
+ }
+ }
+ for (j = 0; j < num_roles; j++) {
+ if (found[j] != 1) {
+ printf("role %s associated with user %s %d times\n", role_names[j], user_name, found[j]);
+ CU_FAIL("user mapping failure\n");
+ }
+ }
+ free(found);
+ CU_ASSERT_EQUAL(extra, 0);
+}
+
+void test_expander_user_mapping(void)
+{
+ char *roles1[] = { "user_check_1_1_r", "user_check_1_2_r" };
+
+ check_user_roles(&user_expanded, "user_check_1", roles1, 2);
+}
diff --git a/tests/test-expander-users.h b/tests/test-expander-users.h
new file mode 100644
index 0000000..cb12143
--- /dev/null
+++ b/tests/test-expander-users.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_USER_H__
+#define __TEST_EXPANDER_USER_H__
+
+void test_expander_user_mapping(void);
+
+#endif
diff --git a/tests/test-expander.c b/tests/test-expander.c
new file mode 100644
index 0000000..ded1d9d
--- /dev/null
+++ b/tests/test-expander.c
@@ -0,0 +1,218 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This is where the expander tests should go, including:
+ * - check role, type, bool, user mapping
+ * - add symbols declared in enabled optionals
+ * - do not add symbols declared in disabled optionals
+ * - add rules from enabled optionals
+ * - do not add rules from disabled optionals
+ * - verify attribute mapping
+
+ * - check conditional expressions for correct mapping
+ */
+
+#include "test-expander.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-expander-users.h"
+#include "test-expander-roles.h"
+#include "test-expander-attr-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <stdlib.h>
+
+policydb_t role_expanded;
+policydb_t user_expanded;
+policydb_t base_expanded2;
+static policydb_t basemod;
+static policydb_t basemod2;
+static policydb_t mod2;
+static policydb_t base_expanded;
+static policydb_t base_only_mod;
+static policydb_t base_only_expanded;
+static policydb_t role_basemod;
+static policydb_t role_mod;
+static policydb_t user_basemod;
+static policydb_t user_mod;
+static policydb_t alias_basemod;
+static policydb_t alias_mod;
+static policydb_t alias_expanded;
+static uint32_t *typemap;
+extern int mls;
+
+/* Takes base, some number of modules, links them, and expands them
+ reads source from myfiles array, which has the base string followed by
+ each module string */
+int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, char **myfiles)
+{
+ char *filename[num_modules + 1];
+ int i;
+
+ for (i = 0; i < num_modules + 1; i++) {
+ filename[i] = calloc(PATH_MAX, sizeof(char));
+ if (snprintf(filename[i], PATH_MAX, "policies/test-expander/%s%s", myfiles[i], mls ? ".mls" : ".std") < 0)
+ return -1;
+ }
+
+ if (policydb_init(mybase)) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ for (i = 0; i < num_modules; i++) {
+ if (policydb_init(mymodules[i])) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+ }
+
+ if (policydb_init(myexpanded)) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ mybase->policy_type = POLICY_BASE;
+ mybase->mls = mls;
+
+ if (read_source_policy(mybase, filename[0], myfiles[0])) {
+ fprintf(stderr, "read source policy failed %s\n", filename[0]);
+ return -1;
+ }
+
+ for (i = 1; i < num_modules + 1; i++) {
+ mymodules[i - 1]->policy_type = POLICY_MOD;
+ mymodules[i - 1]->mls = mls;
+ if (read_source_policy(mymodules[i - 1], filename[i], myfiles[i])) {
+ fprintf(stderr, "read source policy failed %s\n", filename[i]);
+ return -1;
+ }
+ }
+
+ if (link_modules(NULL, mybase, mymodules, num_modules, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ if (expand_module(NULL, mybase, myexpanded, 0, 0)) {
+ fprintf(stderr, "expand modules failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int expander_test_init(void)
+{
+ char *small_base_file = "small-base.conf";
+ char *base_only_file = "base-base-only.conf";
+ int rc;
+ policydb_t *mymod2;
+ char *files2[] = { "small-base.conf", "module.conf" };
+ char *role_files[] = { "role-base.conf", "role-module.conf" };
+ char *user_files[] = { "user-base.conf", "user-module.conf" };
+ char *alias_files[] = { "alias-base.conf", "alias-module.conf" };
+
+ rc = expander_policy_init(&basemod, 0, NULL, &base_expanded, &small_base_file);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &mod2;
+ rc = expander_policy_init(&basemod2, 1, &mymod2, &base_expanded2, files2);
+ if (rc != 0)
+ return rc;
+
+ rc = expander_policy_init(&base_only_mod, 0, NULL, &base_only_expanded, &base_only_file);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &role_mod;
+ rc = expander_policy_init(&role_basemod, 1, &mymod2, &role_expanded, role_files);
+ if (rc != 0)
+ return rc;
+
+ /* Just init the base for now, until we figure out how to separate out
+ mls and non-mls tests since users can't be used in mls module */
+ mymod2 = &user_mod;
+ rc = expander_policy_init(&user_basemod, 0, NULL, &user_expanded, user_files);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &alias_mod;
+ rc = expander_policy_init(&alias_basemod, 1, &mymod2, &alias_expanded, alias_files);
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
+int expander_test_cleanup(void)
+{
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+ free(typemap);
+
+ return 0;
+}
+
+static void test_expander_indexes(void)
+{
+ test_policydb_indexes(&base_expanded);
+}
+
+static void test_expander_alias(void)
+{
+ test_alias_datum(&alias_expanded, "alias_check_1_a", "alias_check_1_t", 1, 0);
+ test_alias_datum(&alias_expanded, "alias_check_2_a", "alias_check_2_t", 1, 0);
+ test_alias_datum(&alias_expanded, "alias_check_3_a", "alias_check_3_t", 1, 0);
+}
+
+int expander_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "expander_indexes", test_expander_indexes)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "expander_attr_mapping", test_expander_attr_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "expander_role_mapping", test_expander_role_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "expander_user_mapping", test_expander_user_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "expander_alias", test_expander_alias)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/tests/test-expander.h b/tests/test-expander.h
new file mode 100644
index 0000000..5964133
--- /dev/null
+++ b/tests/test-expander.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_H__
+#define __TEST_EXPANDER_H__
+
+#include <CUnit/Basic.h>
+
+int expander_test_init(void);
+int expander_test_cleanup(void);
+int expander_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/tests/test-linker-cond-map.c b/tests/test-linker-cond-map.c
new file mode 100644
index 0000000..0ef0d69
--- /dev/null
+++ b/tests/test-linker-cond-map.c
@@ -0,0 +1,159 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for conditionals
+ * Test each cond/bool for these
+ * - boolean copied correctly (state is correct)
+ * - conditional expression is correct
+ * Tests:
+ * - single boolean in base
+ * - single boolean in module
+ * - single boolean in base optional
+ * - single boolean in module optional
+ * - 2 booleans in base
+ * - 2 booleans in module
+ * - 2 booleans in base optional
+ * - 2 booleans in module optional
+ * - 2 booleans, base and module
+ * - 2 booleans, base optional and module
+ * - 2 booleans, base optional and module optional
+ * - 3 booleans, base, base optional, module
+ * - 4 boolean, base, base optional, module, module optional
+ */
+
+typedef struct test_cond_expr {
+ char *bool;
+ uint32_t expr_type;
+} test_cond_expr_t;
+
+void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len)
+{
+ int i;
+ cond_expr_t *expr;
+
+ CU_ASSERT_FATAL(d->cond_list != NULL);
+ CU_ASSERT_FATAL(d->cond_list->expr != NULL);
+
+ expr = d->cond_list->expr;
+
+ for (i = 0; i < len; i++) {
+ CU_ASSERT_FATAL(expr != NULL);
+
+ CU_ASSERT(expr->expr_type == bools[i].expr_type);
+ if (bools[i].bool) {
+ CU_ASSERT(strcmp(p->sym_val_to_name[SYM_BOOLS][expr->bool - 1], bools[i].bool) == 0);
+ }
+ expr = expr->next;
+ }
+}
+
+void test_bool_state(policydb_t * p, char *bool, int state)
+{
+ cond_bool_datum_t *b;
+
+ b = hashtab_search(p->p_bools.table, bool);
+ CU_ASSERT_FATAL(b != NULL);
+ CU_ASSERT(b->state == state);
+}
+
+void base_cond_tests(policydb_t * base)
+{
+ avrule_decl_t *d;
+ unsigned int decls[1];
+ test_cond_expr_t bools[2];
+
+ /* these tests look at booleans and conditionals in the base only
+ * to ensure that they aren't altered or removed during the link process */
+
+ /* bool existance and state, global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_b_bool_1", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_b_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, optional scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o1_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "o1_b_bool_1", 1);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "o1_b_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+}
+
+void module_cond_tests(policydb_t * base)
+{
+ avrule_decl_t *d;
+ unsigned int decls[1];
+ test_cond_expr_t bools[3];
+
+ /* bool existance and state, module 1 global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_m1_bool_1", 1);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_m1_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, module 1 optional scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o1_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "o1_m1_bool_1", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "o1_m1_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, module 2 global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_m2_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_sym_presence(base, "g_m2_bool_2", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_m2_bool_1", 1);
+ test_bool_state(base, "g_m2_bool_2", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_m2_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ bools[1].bool = "g_m2_bool_2";
+ bools[1].expr_type = COND_BOOL;
+ bools[2].bool = NULL;
+ bools[2].expr_type = COND_AND;
+ test_cond_expr_mapping(base, d, bools, 3);
+}
diff --git a/tests/test-linker-cond-map.h b/tests/test-linker-cond-map.h
new file mode 100644
index 0000000..148c6f6
--- /dev/null
+++ b/tests/test-linker-cond-map.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_COND_MAP_H__
+#define __TEST_LINKER_COND_MAP_H__
+
+extern void base_cond_tests(policydb_t * base);
+extern void module_cond_tests(policydb_t * base);
+
+#endif
diff --git a/tests/test-linker-roles.c b/tests/test-linker-roles.c
new file mode 100644
index 0000000..42f92d3
--- /dev/null
+++ b/tests/test-linker-roles.c
@@ -0,0 +1,206 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for roles:
+ * Test for each of these for
+ * - role in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type_set
+ * - scope datum has correct decl ids
+ * - dominates bitmap is correct
+ * Tests:
+ * - role in base, no modules
+ * - role in base optional, no modules
+ * - role a in base, b in module
+ * - role a in base and module (additive)
+ * - role a in base and 2 module
+ * - role a in base optional, b in module
+ * - role a in base, b in module optional
+ * - role a in base optional, b in module optional
+ * - role a in base optional and module
+ * - role a in base and module optional
+ * - role a in base optional and module optional
+ * - role a in base optional and 2 modules
+ * - role a and b in base, b dom a, are types correct (TODO)
+ */
+
+/* this simply tests whether the passed in role only has its own
+ * value in its dominates ebitmap */
+static void only_dominates_self(policydb_t * p, role_datum_t * role)
+{
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ int found = 0;
+
+ ebitmap_for_each_bit(&role->dominates, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ found++;
+ CU_ASSERT(i == role->s.value - 1);
+ }
+ }
+ CU_ASSERT(found == 1);
+}
+
+void base_role_tests(policydb_t * base)
+{
+ avrule_decl_t *decl;
+ role_datum_t *role;
+ unsigned int decls[2];
+ char *types[2];
+
+ /* These tests look at roles in the base only, the desire is to ensure that
+ * roles are not destroyed or otherwise removed during the link process */
+
+ /**** test for g_b_role_1 in base and decl 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (g_b_type_1, no negset, no flags) */
+ types[0] = "g_b_type_1";
+ role = test_role_type_set(base, "g_b_role_1", NULL, types, 1, 0);
+ /* This role should only dominate itself */
+ only_dominates_self(base, role);
+
+ /**** test for o1_b_role_1 in optional (decl 2) ****/
+ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ decls[0] = decl->decl_id;
+ test_sym_presence(base, "o1_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (o1_b_type_1, no negset, no flags) */
+ types[0] = "o1_b_type_1";
+ role = test_role_type_set(base, "o1_b_role_1", decl, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+}
+
+void module_role_tests(policydb_t * base)
+{
+ role_datum_t *role;
+ avrule_decl_t *decl;
+ unsigned int decls[2];
+ char *types[3];
+
+ /* These tests are run when the base is linked with 2 modules,
+ * They should test whether the roles get copied correctly from the
+ * modules into the base */
+
+ /**** test for role in module 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "g_m1_role_1", NULL, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in module 1 (optional) ****/
+ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ decls[0] = decl->decl_id;
+ test_sym_presence(base, "o1_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (o1_m1_type_1, no negset, no flags) */
+ types[0] = "o1_m1_type_1";
+ role = test_role_type_set(base, "o1_m1_role_1", decl, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /* These test whether the type sets are copied to the right place and
+ * correctly unioned when they should be */
+
+ /**** test for type added to base role in module 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+ types[0] = "g_b_type_2"; /* added in base when declared */
+ types[1] = "g_m1_type_1"; /* added in module */
+ role = test_role_type_set(base, "g_b_role_2", NULL, types, 2, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for type added to base role in module 1 & 2 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+ test_sym_presence(base, "g_b_role_3", SYM_ROLES, SCOPE_DECL, decls, 3);
+ /* make sure it has the correct type set (g_b_type_2, g_m1_type_2, g_m2_type_2, no negset, no flags) */
+ types[0] = "g_b_type_2"; /* added in base when declared */
+ types[1] = "g_m1_type_2"; /* added in module 1 */
+ types[2] = "g_m2_type_2"; /* added in module 2 */
+ role = test_role_type_set(base, "g_b_role_3", NULL, types, 3, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base optional and module 1 (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "o1_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "o1_b_role_2", NULL, types, 1, 0);
+ types[0] = "o1_b_type_1";
+ role = test_role_type_set(base, "o1_b_role_2", test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"))->decl_id;
+ test_sym_presence(base, "g_b_role_4", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+ types[0] = "g_b_type_2";
+ role = test_role_type_set(base, "g_b_role_4", NULL, types, 1, 0);
+ types[0] = "g_m1_type_2";
+ role = test_role_type_set(base, "g_b_role_4", test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+ test_sym_presence(base, "o3_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the 3rd base optional and one in the 3rd module optional */
+ types[0] = "o3_b_type_1";
+ role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"), types, 1, 0);
+ types[0] = "o3_m1_type_1";
+ role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+ test_sym_presence(base, "o4_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 3);
+ /* this one will have 2 type sets, one in the global symtab (with both module types) and one in the 4th optional of base */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "o4_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"), types, 1, 0);
+ types[0] = "g_m2_type_1";
+ types[1] = "g_m1_type_2";
+ role = test_role_type_set(base, "o4_b_role_1", NULL, types, 2, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+}
diff --git a/tests/test-linker-roles.h b/tests/test-linker-roles.h
new file mode 100644
index 0000000..f7407df
--- /dev/null
+++ b/tests/test-linker-roles.h
@@ -0,0 +1,29 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_ROLES_H__
+#define __TEST_LINKER_ROLES_H__
+
+#include <sepol/policydb/policydb.h>
+
+extern void base_role_tests(policydb_t * base);
+extern void module_role_tests(policydb_t * base);
+
+#endif
diff --git a/tests/test-linker-types.c b/tests/test-linker-types.c
new file mode 100644
index 0000000..94f16ac
--- /dev/null
+++ b/tests/test-linker-types.c
@@ -0,0 +1,317 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for types:
+ * Test for each of these for
+ * - type in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type bitmap (if attr)
+ * - primary is set correctly
+ * - scope datum has correct decl ids
+ * Tests:
+ * - type in base, no modules
+ * - type in base optional, no modules
+ * - type a in base, b in module
+ * - type a in base optional, b in module
+ * - type a in base, b in module optional
+ * - type a in base optional, b in module optional
+ * - attr in base, no modules
+ * - attr in base optional, no modules
+ * - attr a in base, b in module
+ * - attr a in base optional, b in module
+ * - attr a in base, b in module optional
+ * - attr a in base optional, b in module optional
+ * - attr a declared in base, added to in module
+ * - attr a declared in base, added to in module optional
+ * - attr a declared in base, added to in 2 modules
+ * - attr a declared in base, added to in 2 modules (optional and global)
+ * - attr a declared in base optional, added to in module
+ * - attr a declared in base optional, added to in module optional
+ * - attr a added to in base optional, declared in module
+ * - attr a added to in base optional, declared in module optional
+ * - attr a added to in base optional, declared in module, added to in other module
+ * - attr a added to in base optional, declared in module optional, added to in other module
+ * - attr a added to in base optional, declared in module , added to in other module optional
+ * - attr a added to in base optional, declared in module optional, added to in other module optional
+ * - alias in base of primary type in base, no modules
+ * - alias in base optional of primary type in base, no modules
+ * - alias in base optional of primary type in base optional
+ * - alias in module of primary type in base
+ * - alias in module optional of primary type in base
+ * - alias in module optional of primary type in base optional
+ * - alias in module of primary type in module
+ * - alias in module optional of primary type in module
+ * - alias in module optional of primary type in module optional
+ * - alias a in base, b in module, primary type in base
+ * - alias a in base, b in module, primary type in module
+ * - alias a in base optional, b in module, primary type in base
+ * - alias a in base optional, b in module, primary type in module
+ * - alias a in base, b in module optional, primary type in base
+ * - alias a in base, b in module optional, primary type in module
+ * - alias a in base optional, b in module optional, primary type in base
+ * - alias a in base optional, b in module optional, primary type in module
+ * - alias a in base, required in module, primary type in base
+ * - alias a in base, required in base optional, primary type in base
+ * - alias a in base, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in base
+ * - alias a in module, required in module optional, primary type in base
+ * - alias a in base optional, required in module, primary type in base
+ * - alias a in base optional, required in different base optional, primary type in base
+ * - alias a in base optional, required in module optional, primary type in base
+ * - alias a in module optional, required in base optional, primary type in base
+ * - alias a in module optional, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in module
+ * - alias a in module, required in module optional, primary type in module
+ * - alias a in base optional, required in module, primary type in module
+ * - alias a in base optional, required in different base optional, primary type in module
+ * - alias a in base optional, required in module optional, primary type in module
+ * - alias a in module optional, required in base optional, primary type in module
+ * - alias a in module optional, required in module optional, primary type in module
+ */
+
+/* Don't pass in decls from global blocks since symbols aren't stored in their symtab */
+static void test_type_datum(policydb_t * p, char *id, unsigned int *decls, int len, unsigned int primary)
+{
+ int i;
+ unsigned int value;
+ type_datum_t *type;
+
+ /* just test the type datums for each decl to see if it is what we expect */
+ type = hashtab_search(p->p_types.table, id);
+
+ CU_ASSERT_FATAL(type != NULL);
+ CU_ASSERT(type->primary == primary);
+ CU_ASSERT(type->flavor == TYPE_TYPE);
+
+ value = type->s.value;
+
+ for (i = 0; i < len; i++) {
+ type = hashtab_search(p->decl_val_to_struct[decls[i] - 1]->p_types.table, id);
+ CU_ASSERT_FATAL(type != NULL);
+ CU_ASSERT(type->primary == primary);
+ CU_ASSERT(type->flavor == TYPE_TYPE);
+ CU_ASSERT(type->s.value == value);
+ }
+
+}
+
+void base_type_tests(policydb_t * base)
+{
+ unsigned int decls[2];
+ char *types[2];
+
+ /* These tests look at types in the base only, the desire is to ensure that
+ * types are not destroyed or otherwise removed during the link process.
+ * if this happens these tests won't work anyway since we are using types to
+ * mark blocks */
+
+ /**** test for g_b_type_1 in base and decl 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "g_b_type_1", NULL, 0, 1);
+ /* this attr is in the same decl as the type */
+ test_sym_presence(base, "g_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_b_type_1";
+ test_attr_types(base, "g_b_attr_1", NULL, types, 1);
+
+ /**** test for o1_b_type_1 in optional (decl 2) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ test_sym_presence(base, "o1_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "o1_b_type_1", NULL, 0, 1);
+ /* this attr is in the same decl as the type */
+ test_sym_presence(base, "o1_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o1_b_type_1";
+ test_attr_types(base, "o1_b_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* tests for aliases */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_b_alias_1", "g_b_type_3", 1, 0);
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o6_b"))->decl_id;
+ test_sym_presence(base, "g_b_alias_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_b_alias_2", "g_b_type_3", 1, 0);
+
+}
+
+void module_type_tests(policydb_t * base)
+{
+ unsigned int decls[2];
+ char *types[2];
+ avrule_decl_t *d;
+
+ /* These tests look at types that were copied from modules or attributes
+ * that were modified and declared in modules and base. These apply to
+ * declarations and modifications in and out of optionals. These tests
+ * should ensure that types and attributes are correctly copied from modules
+ * and that attribute type sets are correctly copied and mapped. */
+
+ /* note: scope for attributes is currently smashed if the attribute is declared
+ * somewhere so the scope test only looks at global, the type bitmap test looks
+ * at the appropriate decl symtab */
+
+ /* test for type in module 1 (global) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "g_m1_type_1", NULL, 0, 1);
+ /* attr has is in the same decl as the above type */
+ test_sym_presence(base, "g_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_1";
+ types[1] = "g_m1_type_2";
+ test_attr_types(base, "g_m1_attr_1", NULL, types, 2);
+
+ /* test for type in module 1 (optional) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+ test_sym_presence(base, "o1_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "o1_m1_type_1", NULL, 0, 1);
+ /* attr has is in the same decl as the above type */
+ test_sym_presence(base, "o1_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o1_m1_type_2";
+ test_attr_types(base, "o1_m1_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* test for attr declared in base, added to in module (global).
+ * Since these are both global it'll be merged in the main symtab */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_3";
+ test_attr_types(base, "g_b_attr_3", NULL, types, 1);
+
+ /* test for attr declared in base, added to in module (optional). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+ types[0] = "o1_m1_type_3";
+ test_attr_types(base, "g_b_attr_4", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* test for attr declared in base, added to in 2 modules (global). (merged in main symtab) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_5", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_4";
+ types[1] = "g_m2_type_4";
+ test_attr_types(base, "g_b_attr_5", NULL, types, 2);
+
+ /* test for attr declared in base, added to in 2 modules (optional/global). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_6", SYM_TYPES, SCOPE_DECL, decls, 1);
+ /* module 2 was global to its type is in main symtab */
+ types[0] = "g_m2_type_5";
+ test_attr_types(base, "g_b_attr_6", NULL, types, 1);
+ d = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"));
+ types[0] = "o3_m1_type_2";
+ test_attr_types(base, "g_b_attr_6", d, types, 1);
+
+ /* test for attr declared in base optional, added to in module (global). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+ test_sym_presence(base, "o4_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_5";
+ test_attr_types(base, "o4_b_attr_1", NULL, types, 1);
+
+ /* test for attr declared in base optional, added to in module (optional). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ test_sym_presence(base, "o1_b_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ types[0] = "o1_m1_type_5";
+ test_attr_types(base, "o1_b_attr_2", d, types, 1);
+
+ /* test for attr declared in module, added to in base optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ types[0] = "o1_b_type_2";
+ test_attr_types(base, "g_m1_attr_2", d, types, 1);
+
+ /* test for attr declared in module optional, added to in base optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+ test_sym_presence(base, "o3_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+ types[0] = "o4_b_type_1";
+ test_attr_types(base, "o3_m1_attr_1", d, types, 1);
+
+ /* attr a added to in base optional, declared/added to in module, added to in other module */
+ /* first the module declare/add and module 2 add (since its global it'll be in the main symtab */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_6";
+ types[1] = "g_m2_type_3";
+ test_attr_types(base, "g_m1_attr_3", NULL, types, 2);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+ types[0] = "o4_b_type_2";
+ test_attr_types(base, "g_m1_attr_3", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module optional, added to in other module */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o3_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o3_m1_type_3";
+ test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+ /* module 2's type will be in the main symtab */
+ types[0] = "g_m2_type_6";
+ test_attr_types(base, "o3_m1_attr_2", NULL, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_b");
+ types[0] = "o2_b_type_1";
+ test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module , added to in other module optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_7";
+ test_attr_types(base, "g_m1_attr_4", NULL, types, 1);
+ /* module 2 */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+ types[0] = "o2_m2_type_1";
+ test_attr_types(base, "g_m1_attr_4", d, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+ types[0] = "o5_b_type_1";
+ test_attr_types(base, "g_m1_attr_4", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module optional, added to in other module optional */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o4_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o4_m1_type_1";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+ /* module 2 */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+ types[0] = "o2_m2_type_2";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+ types[0] = "o5_b_type_2";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+
+ /* tests for aliases */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_m_alias_1", "g_b_type_3", 1, 0);
+
+}
diff --git a/tests/test-linker-types.h b/tests/test-linker-types.h
new file mode 100644
index 0000000..0c860eb
--- /dev/null
+++ b/tests/test-linker-types.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_TYPES_H__
+#define __TEST_LINKER_TYPES_H__
+
+extern void base_type_tests(policydb_t * base);
+extern void module_type_tests(policydb_t * base);
+
+#endif
diff --git a/tests/test-linker.c b/tests/test-linker.c
new file mode 100644
index 0000000..d08f219
--- /dev/null
+++ b/tests/test-linker.c
@@ -0,0 +1,154 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This is where the linker tests should go, including:
+ * - check role, type, bool, user, attr mapping
+ * - check for properly enabled optional
+ * - check for properly disabled optional
+ * - check for non-optional disabled blocks
+ * - properly add symbols declared in optionals
+ */
+
+#include "test-linker.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-linker-roles.h"
+#include "test-linker-types.h"
+#include "test-linker-cond-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define NUM_MODS 2
+#define NUM_POLICIES NUM_MODS+1
+
+#define BASEMOD NUM_MODS
+const char *policies[NUM_POLICIES] = {
+ "module1.conf",
+ "module2.conf",
+ "small-base.conf",
+};
+
+static policydb_t basenomods;
+static policydb_t linkedbase;
+static policydb_t *modules[NUM_MODS];
+extern int mls;
+
+int linker_test_init(void)
+{
+ int i;
+
+ if (test_load_policy(&linkedbase, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+ return -1;
+
+ if (test_load_policy(&basenomods, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+ return -1;
+
+ for (i = 0; i < NUM_MODS; i++) {
+
+ modules[i] = calloc(1, sizeof(*modules[i]));
+ if (!modules[i]) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ if (test_load_policy(modules[i], POLICY_MOD, mls, "test-linker", policies[i]))
+ return -1;
+
+ }
+
+ if (link_modules(NULL, &linkedbase, modules, NUM_MODS, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ if (link_modules(NULL, &basenomods, NULL, 0, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int linker_test_cleanup(void)
+{
+ int i;
+
+ policydb_destroy(&basenomods);
+ policydb_destroy(&linkedbase);
+
+ for (i = 0; i < NUM_MODS; i++) {
+ policydb_destroy(modules[i]);
+ free(modules[i]);
+ }
+ return 0;
+}
+
+static void test_linker_indexes(void)
+{
+ test_policydb_indexes(&linkedbase);
+}
+
+static void test_linker_roles(void)
+{
+ base_role_tests(&basenomods);
+ base_role_tests(&linkedbase);
+ module_role_tests(&linkedbase);
+}
+
+static void test_linker_types(void)
+{
+ base_type_tests(&basenomods);
+ base_type_tests(&linkedbase);
+ module_type_tests(&linkedbase);
+}
+
+static void test_linker_cond(void)
+{
+ base_cond_tests(&basenomods);
+ base_cond_tests(&linkedbase);
+ module_cond_tests(&linkedbase);
+}
+
+int linker_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "linker_indexes", test_linker_indexes)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_types", test_linker_types)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_roles", test_linker_roles)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_cond", test_linker_cond)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/tests/test-linker.h b/tests/test-linker.h
new file mode 100644
index 0000000..16339a0
--- /dev/null
+++ b/tests/test-linker.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_H__
+#define __TEST_LINKER_H__
+
+#include <CUnit/Basic.h>
+
+int linker_test_init(void);
+int linker_test_cleanup(void);
+int linker_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644
index 0000000..6864114
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,24 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+BINDIR ?= $(PREFIX)/bin
+
+CFLAGS ?= -Wall -Werror
+override CFLAGS += -I../include
+LDLIBS += -L../src -lsepol
+
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+
+all: $(TARGETS)
+
+install: all
+ -mkdir -p $(BINDIR)
+ install -m 755 $(TARGETS) $(BINDIR)
+
+clean:
+ -rm -f $(TARGETS) *.o
+
+indent:
+ ../../scripts/Lindent $(wildcard *.[ch])
+
+relabel:
+
diff --git a/utils/chkcon.c b/utils/chkcon.c
new file mode 100644
index 0000000..4c23d4c
--- /dev/null
+++ b/utils/chkcon.c
@@ -0,0 +1,42 @@
+#include <sepol/sepol.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+void usage(char *progname)
+{
+ printf("usage: %s policy context\n", progname);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+
+ if (argc != 3)
+ usage(argv[0]);
+
+ fp = fopen(argv[1], "r");
+ if (!fp) {
+ fprintf(stderr, "Can't open '%s': %s\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+ if (sepol_set_policydb_from_file(fp) < 0) {
+ fprintf(stderr, "Error while processing %s: %s\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+ fclose(fp);
+
+ if (sepol_check_context(argv[2]) < 0) {
+ fprintf(stderr, "%s is not valid\n", argv[2]);
+ exit(1);
+ }
+
+ printf("%s is valid\n", argv[2]);
+ exit(0);
+}