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