pax_global_header00006660000000000000000000000064131414226240014511gustar00rootroot0000000000000052 comment=e03617eb7ab5a035633bff66500b95d25232e331 setools-4.1.1/000077500000000000000000000000001314142262400132045ustar00rootroot00000000000000setools-4.1.1/.coveragerc000066400000000000000000000003451314142262400153270ustar00rootroot00000000000000#coverage.py configuration [run] source = setools # This is SWIG generated: omit = setools/policyrep/qpol.py [report] exclude_lines = pragma: no cover def __repr__ raise NotImplementedError return NotImplemented setools-4.1.1/.gitignore000066400000000000000000000004501314142262400151730ustar00rootroot00000000000000/build /dist /setools.egg-info *.pyc *.pyo libqpol/policy_parse.c libqpol/policy_parse.h libqpol/policy_scan.c setools/policyrep/qpol_wrap.c setools/policyrep/qpol.py *.so # Qt Generated Help files qhc/apol.qch qhc/apol.qhc # Generated by tox /.tox # Generated by coverage /htmlcov /.coverage setools-4.1.1/.pylintrc000066400000000000000000000265541314142262400150650ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS,qpol.py # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. jobs=1 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist= # Allow optimization of some AST trees. This will activate a peephole AST # optimizer, which will apply various small optimizations. For instance, it can # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting # AST will be different than the one from reality. optimize-ast=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # format: enforced by pep8 tool disable=I,logging-format-interpolation,format,similarities [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,s,t,ex,fs,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=no # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Naming hint for constant names const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for function names function-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for variable names variable-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [ELIF] # Maximum number of nested blocks for function / method body max-nested-blocks=5 [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SPELLING] # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [FORMAT] # Maximum number of characters on a single line. max-line-length=100 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). This supports can work # with qualified names. ignored-classes= # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_,_cb [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=optparse # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [DESIGN] # Maximum number of arguments for function / method max-args=20 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=20 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=15 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=20 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict,_fields,_replace,_source,_make [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception setools-4.1.1/.travis.yml000066400000000000000000000033131314142262400153150ustar00rootroot00000000000000# SELinux userspace portions originally by Nicolas Iooss # from: https://github.com/fishilico/selinux-refpolicy-patched/blob/travis-upstream/.travis.yml --- language: python env: - TOX_ENV=py27 - TOX_ENV=py33 - TOX_ENV=py34 - TOX_ENV=py35 - TOX_ENV=pep8 - TOX_ENV=coverage - TOX_ENV=lint matrix: fast_finish: true allow_failures: - env: TOX_ENV=coverage sudo: required dist: trusty addons: apt: packages: # Install SELinux userspace utilities dependencies - bison - flex - gettext - libaudit-dev - libbz2-dev - libustr-dev - libpcre3-dev before_install: - lsb_release -a - bison -V - flex -V - python -V install: - SELINUX_USERSPACE_VERSION=libsepol-2.7 # Install newer swig - curl -sS -L http://prdownloads.sourceforge.net/swig/swig-3.0.8.tar.gz | tar xz - cd swig-3.0.8 - ./configure - make - sudo make install - cd .. # Download current SELinux userspace tools and libraries - git clone https://github.com/SELinuxProject/selinux.git selinux-src -b ${SELINUX_USERSPACE_VERSION} # Only portions of the toolchain are necessary - sed -i -e 's/^SUBDIRS=.*/SUBDIRS=libsepol libselinux checkpolicy/' selinux-src/Makefile # Compile and install SELinux toolchain # On Ubuntu 12.04, default CFLAGS make the build fail in libsepol/cil with: # error: declaration of 'index' shadows a global declarationo - sudo make CFLAGS="-O2 -pipe -fPIC -Wall" -C selinux-src install # Ubuntu 12.04's flex generates a redundant decl in libqpol - sed -i -e "/Wwrite-strings/s/,/, '-Wno-redundant-decls',/" setup.py - pip install tox script: - tox --version - tox -e $TOX_ENV after_failure: - cat "${TRAVIS_BUILD_DIR}/.tox/tox-0.log" setools-4.1.1/COPYING000066400000000000000000000006611314142262400142420ustar00rootroot00000000000000The intent is to allow free use of this source code. All programs' source files are copyright protected and freely distributed under the GNU General Public License (see COPYING.GPL). All library source files are copyright under the GNU Lesser General Public License (see COPYING.LGPL). All files distributed with this package indicate the appropriate license to use with that file. Absolutely no warranty is provided or implied. setools-4.1.1/COPYING.GPL000066400000000000000000000432541314142262400146700ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 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 Lesser 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. Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. , 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 Lesser General Public License instead of this License. setools-4.1.1/COPYING.LGPL000066400000000000000000000636421314142262400150070ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! setools-4.1.1/ChangeLog000066400000000000000000000033301314142262400147550ustar00rootroot00000000000000*setools-4.1.0-rc (11 Dec 2016) Library: * Implemented support for alternate install prefixes. * Implemented support for building setools with a locally-built libsepol. * Fixed an sediff bug with unioning rules after expansion. * Improved sediff memory usage. * Patch from Nicolas Iooss to make more stable output in TE rule permission lists. * Replaced string representations (e.g. rule types) with enumerations. Requires the enum34 (not enum) Python package if using Python < 3.4. Apol: * Implemented context menu option for exporting the information flow and domain transition analysis tree browser views. * Implemented CSV export of table results. * Implemented (clipboard) copy from table results. * Added missing "clear" button in object class query. * Implemented save/load settings for tabs. * Implemented save/load workspace (save all tabs settings). * Fixed include/exclude type dialog to keep its place when adding or removing types from an analysis. * Implemented filter on include/exclude type dialog to filter the lists by attribute. *setools-4.0.1 (17 May 2016) Library: * Fixed a compile error on 32bit systems. * Changed domain transition analysis output to use lists instead of generators. This fixes a display problem in apol's DTA browser. Apol: * Replaced icons with stock Qt icons to remove license issues with some distributions. Sesearch: * Changed xperm options to bring in line with sediff, e.g. --allowx changed to --allowxperm. Python's argument parser will still detect --allowx as an abbreviation of --allowxperm, so compatibility is preserved. *setools-4.0.0 (04 May 2016) First 4.0 release. SETools is reimplemented in Python. setools-4.1.1/KNOWN-BUGS000066400000000000000000000012211314142262400145550ustar00rootroot00000000000000The following is a list of known bugs with SETools. * If you are using Python 3.5 and see errors like this: SystemError: returned a result with an error set This is a bug in the wrapper generated by SWIG. This has been seen on SWIG versions 2.0.12 and 3.0.7. Upgrading to SWIG 3.0.8+ and rebuilding SETools should address this issue. * A bug in NetworkX 1.8+ will output the following message to stderr if a type is valid, but not a node in a domain transition or information flow graph: 'Type' object is not iterable This message may be seen multiple times at the end of running unit tests. setools-4.1.1/MANIFEST.in000066400000000000000000000005071314142262400147440ustar00rootroot00000000000000include ChangeLog include COPYING* include libqpol/*.h include libqpol/*.l include libqpol/*.y include libqpol/include/qpol/*.h include man/* include qhc/* include setools/perm_map include setoolsui/*.ui include setoolsui/apol/*.ui include setoolsui/apol/apol.qhc include tests/*.conf include tests/*.py include tests/perm_map setools-4.1.1/README.md000066400000000000000000000125051314142262400144660ustar00rootroot00000000000000# SETools: Policy analysis tools for SELinux https://github.com/TresysTechnology/setools/wiki ## Overview This file describes SETools, developed by Tresys Technology. SETools is a collection of graphical tools, command-line tools, and libraries designed to facilitate SELinux policy analysis. Please consult the KNOWN-BUGS file prior to reporting bugs. ## Installation SETools uses the Python setuptools build system to build, and install. As such it contains a setup.py script that will install the tools. To run SETools command line tools, the following packages are required: * Python 2.7 or 3.3+ * NetworkX 1.8+ * setuptools * enum34 (on Python 2.7 and 3.3 only) * libselinux Python bindings (optional but recommended) To run SETools graphical tools, the following packages are also required: * PyQt5 * qt5-assistant * qt-devel (only if rebuilding the help file) To build SETools, the following development packages are required, in addition to the development packages from the above list: * gcc * bison * flex * libsepol 2.7+ * SWIG 2.0.12+ or 3.0+ (3.0.8+ required for Python 3.5) To run SETools unit tests, the following packages are required, in addition to the above dependencies: * mock (on Python 2.7 only) * tox (optional) ### Obtaining SETools SETools is included in most Linux distributions which support SELinux, such as Fedora, Red Hat Enterprise Linux, Gentoo, and Debian. Official releases of SETools may be freely downloaded from: https://github.com/TresysTechnology/setools/releases SETools source code is maintained within a GitHub repository. From the command line do: ``` $ git clone https://github.com/TresysTechnology/setools.git ``` You may also browse the GitHub repository at https://github.com/TresysTechnology/setools. The master branch has development code that may not be stable. Each release series is considered stable, and has its own branch, e.g. "4.0" for all 4.0.* releases. To checkout a stable branch, do: ``` $ git checkout 4.0 ``` Where `4.0` is the release series. Each release will have a tag. ### Building SETools for Local Use To use SETools locally, without installing it onto the system, unpack the official distribution or check out the git repository, and perform the following at the root: ``` $ python setup.py build_ext -i ``` This will compile the C portion of SETools locally, and then the tools can be ran from the current directory (e.g. ```./seinfo```). ### Rebuilding the Apol Help File For convenience, a prebuilt copy of the apol help data file is included. To rebuild this file, the Qt5 development tools are required (particularly, the ```qcollectiongenerator``` tool). At the root of the SETools soures, perform the following: ``` $ python setup.py build_qhc ``` ### Installing SETools Unpack the official distribution or check out the git repository, and perform the following at the root: ``` $ python setup.py build $ python setup.py install ``` This will put the applications in /usr/bin, data files in /usr/share/setools, and libraries in /usr/lib/pythonX.Y/site-packages/setools. ### Building SETools with a Local Libsepol At times, SETools requires a newer libsepol than is available from distributions. To use a locally-built libsepol instead of the libsepol provided by the Linux distribution, build the libsepol sources and then set the SEPOL_SRC environmental variable to the path to the root of libsepol source tree: ``` $ export SEPOL_SRC=/home/user/src/selinux/libsepol $ python setup.py build $ python setup.py install ``` SEPOL_SRC also applies for building SETools for local use. ### Installation Options Please see `python setup.py --help` or `python setup.py install --help` for up-to-date information on build and install options, respectively. ### Unit Tests One goal for SETools is to provide confidence in the validity of the output for the tools. The unit tests for SETools can be run with the following command ``` $ python setup.py test ``` ## Features SETools encompasses a number of tools, both graphical and command line, and libraries. Many of the programs have help files accessible during runtime. ### Graphical tools Tool Name | Use ---------- | ------------------------------------------- apol | A Qt graphical analysis tool. Use it to perform various types of analyses. ### Command-line tools Tool Name | Use ---------- | ------------------------------------------- sediff | Compare two policies to find differences. sedta | Perform domain transition analyses. seinfo | List policy components. seinfoflow | Perform information flow analyses. sesearch | Search rules (allow, type_transition, etc.) ### Analysis Libraries The SETools libraries are available for use in third-party applications. Although this is not officially supported, we will do our best to maintain API stability. ### Reporting bugs Bugs can be reported in the SETools GitHub issues tracker: https://github.com/TresysTechnology/setools/issues ### Copyright license The intent is to allow free use of this source code. All programs' source files are copyright protected and freely distributed under the GNU General Public License (see COPYING.GPL). All library source files are copyright under the GNU Lesser General Public License (see COPYING.LGPL). All files distributed with this package indicate the appropriate license to use. Absolutely no warranty is provided or implied. setools-4.1.1/apol000077500000000000000000000041571314142262400140740ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import sys import argparse import logging from PyQt5.QtWidgets import QApplication import setools import setoolsgui parser = argparse.ArgumentParser(description="Graphical SELinux policy analysis tool.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", nargs="?", help="Path to the SELinux policy to analyze.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG, filename="/dev/null") console_handler = logging.StreamHandler() if args.debug: console_handler.setLevel(logging.DEBUG) console_handler.setFormatter( logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|%(message)s')) elif args.verbose: console_handler.setLevel(logging.INFO) console_handler.setFormatter(logging.Formatter('%(message)s')) else: console_handler.setLevel(logging.WARNING) console_handler.setFormatter(logging.Formatter('%(message)s')) logging.getLogger().addHandler(console_handler) try: app = QApplication(sys.argv) mainwindow = setoolsgui.ApolMainWindow(args.policy) sys.exit(app.exec_()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/libqpol/000077500000000000000000000000001314142262400146465ustar00rootroot00000000000000setools-4.1.1/libqpol/avrule_query.c000066400000000000000000000221161314142262400175370ustar00rootroot00000000000000 /** * @file * Implementation for the public interface for searching and iterating over avrules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 "iterator_internal.h" #include #include #include #include #include #include #include #include "qpol_internal.h" int qpol_policy_get_avrule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter) { policydb_t *db; avtab_state_t *state; if (iter) { *iter = NULL; } if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } #if 1 // Seems to make sediff/sediffx work better without breaking things if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) { ERR(policy, "%s", "Cannot get avrules: Rules not loaded"); errno = ENOTSUP; return STATUS_ERR; } #endif if ((rule_type_mask & QPOL_RULE_NEVERALLOW) && !qpol_policy_has_capability(policy, QPOL_CAP_NEVERALLOW)) { ERR(policy, "%s", "Cannot get avrules: Neverallow rules requested but not available"); errno = ENOTSUP; return STATUS_ERR; } db = &policy->p->p; state = calloc(1, sizeof(avtab_state_t)); if (state == NULL) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } state->ucond_tab = &db->te_avtab; state->cond_tab = &db->te_cond_avtab; state->rule_type_mask = rule_type_mask; state->node = db->te_avtab.htable[0]; if (qpol_iterator_create (policy, state, avtab_state_get_cur, avtab_state_next, avtab_state_end, avtab_state_size, free, iter)) { free(state); return STATUS_ERR; } if (state->node == NULL || !(state->node->key.specified & state->rule_type_mask)) { avtab_state_next(*iter); } return STATUS_SUCCESS; } int qpol_avrule_get_source_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** source) { policydb_t *db = NULL; avtab_ptr_t avrule = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; avrule = (avtab_ptr_t) rule; *source = (qpol_type_t *) db->type_val_to_struct[avrule->key.source_type - 1]; return STATUS_SUCCESS; } int qpol_avrule_get_target_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** target) { policydb_t *db = NULL; avtab_ptr_t avrule = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; avrule = (avtab_ptr_t) rule; *target = (qpol_type_t *) db->type_val_to_struct[avrule->key.target_type - 1]; return STATUS_SUCCESS; } int qpol_avrule_get_object_class(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_class_t ** obj_class) { policydb_t *db = NULL; avtab_ptr_t avrule = NULL; if (obj_class) { *obj_class = NULL; } if (!policy || !rule || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; avrule = (avtab_ptr_t) rule; *obj_class = (qpol_class_t *) db->class_val_to_struct[avrule->key.target_class - 1]; return STATUS_SUCCESS; } int qpol_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** perms) { avtab_ptr_t avrule = NULL; perm_state_t *ps = NULL; if (perms) { *perms = NULL; } if (!policy || !rule || !perms) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; ps = calloc(1, sizeof(perm_state_t)); if (!ps) { return STATUS_ERR; } if (avrule->key.specified & QPOL_RULE_DONTAUDIT) { ps->perm_set = ~(avrule->datum.data); /* stored as auditdeny flip the bits */ } else { ps->perm_set = avrule->datum.data; } ps->obj_class_val = avrule->key.target_class; if (qpol_iterator_create(policy, (void *)ps, perm_state_get_cur, perm_state_next, perm_state_end, perm_state_size, free, perms)) { return STATUS_ERR; } if (!(ps->perm_set & 1)) /* defaults to bit 0, if off: advance */ perm_state_next(*perms); return STATUS_SUCCESS; } int qpol_avrule_get_xperm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** xperms_iter) { avtab_ptr_t avrule = NULL; xperm_state_t *xps = NULL; avtab_extended_perms_t *xperms = NULL; if (xperms_iter) { *xperms_iter = NULL; } if (!policy || !rule || !xperms_iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; if (!(avrule->key.specified & QPOL_RULE_XPERMS)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } xperms = avrule->datum.xperms; xps = calloc(1, sizeof(xperm_state_t)); if (!xps) { return STATUS_ERR; } xps->xperms = xperms; xps->cur = 0; if (qpol_iterator_create(policy, (void *)xps, xperm_state_get_cur, xperm_state_next, xperm_state_end, xperm_state_size, free, xperms_iter)) { return STATUS_ERR; } if (!((xperms->perms[0] & 1) && ((xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) || xperms->driver == 0))) /* defaults to bit 0, if off: advance */ xperm_state_next(*xperms_iter); return STATUS_SUCCESS; } int qpol_avrule_get_xperm_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, char ** type) { avtab_ptr_t avrule = NULL; avtab_extended_perms_t *xperms = NULL; if (type) { *type = NULL; } if (!policy || !rule || !type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; if (!(avrule->key.specified & QPOL_RULE_XPERMS)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } xperms = avrule->datum.xperms; if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { *type = strdup("ioctl"); } else { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * rule_type) { avtab_ptr_t avrule = NULL; if (rule_type) { *rule_type = 0; } if (!policy || !rule || !rule_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; *rule_type = (avrule->key.specified & (QPOL_RULE_AV | QPOL_RULE_XPERMS)); return STATUS_SUCCESS; } int qpol_avrule_get_is_extended(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_extended) { avtab_ptr_t avrule = NULL; if (is_extended) { *is_extended = 0; } if (!policy || !rule || !is_extended) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; *is_extended = (avrule->key.specified & QPOL_RULE_XPERMS) ? 1 : 0; return STATUS_SUCCESS; } int qpol_avrule_get_cond(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_cond_t ** cond) { avtab_ptr_t avrule = NULL; if (cond) { *cond = NULL; } if (!policy || !rule || !cond) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; *cond = (qpol_cond_t *) avrule->parse_context; return STATUS_SUCCESS; } int qpol_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_enabled) { avtab_ptr_t avrule = NULL; if (is_enabled) { *is_enabled = 0; } if (!policy || !rule || !is_enabled) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; *is_enabled = ((avrule->merged & QPOL_COND_RULE_ENABLED) ? 1 : 0); return STATUS_SUCCESS; } int qpol_avrule_get_which_list(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * which_list) { avtab_ptr_t avrule = NULL; if (which_list) { *which_list = 0; } if (!policy || !rule || !which_list) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } avrule = (avtab_ptr_t) rule; if (!avrule->parse_context) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *which_list = ((avrule->merged & QPOL_COND_RULE_LIST) ? 1 : 0); return STATUS_SUCCESS; } setools-4.1.1/libqpol/bool_query.c000066400000000000000000000115501314142262400171740ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over booleans. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "iterator_internal.h" #include #include "qpol_internal.h" int qpol_policy_get_bool_by_name(const qpol_policy_t * policy, const char *name, qpol_bool_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_bools.table, (hashtab_key_t)name); if (internal_datum == NULL) { ERR(policy, "could not find datum for bool %s", name); *datum = NULL; errno = ENOENT; return STATUS_ERR; } *datum = (qpol_bool_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_bool_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; hash_state_t *hs = NULL; int error = 0; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_bools.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_bool_get_value(const qpol_policy_t * policy, const qpol_bool_t * datum, uint32_t * value) { cond_bool_datum_t *internal_datum; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cond_bool_datum_t *) datum; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_bool_get_state(const qpol_policy_t * policy, const qpol_bool_t * datum, int *state) { cond_bool_datum_t *internal_datum; if (policy == NULL || datum == NULL || state == NULL) { if (state != NULL) *state = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cond_bool_datum_t *) datum; *state = internal_datum->state; return STATUS_SUCCESS; } int qpol_bool_set_state(qpol_policy_t * policy, qpol_bool_t * datum, int state) { cond_bool_datum_t *internal_datum; if (policy == NULL || datum == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cond_bool_datum_t *) datum; internal_datum->state = state; /* re-evaluate conditionals to update the state of their rules */ if (qpol_policy_reevaluate_conds(policy)) { return STATUS_ERR; /* errno already set */ } return STATUS_SUCCESS; } int qpol_bool_set_state_no_eval(qpol_policy_t * policy, qpol_bool_t * datum, int state) { cond_bool_datum_t *internal_datum; if (policy == NULL || datum == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cond_bool_datum_t *) datum; internal_datum->state = state; return STATUS_SUCCESS; } int qpol_bool_get_name(const qpol_policy_t * policy, const qpol_bool_t * datum, const char **name) { cond_bool_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (cond_bool_datum_t *) datum; *name = db->p_bool_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } setools-4.1.1/libqpol/bounds_query.c000066400000000000000000000221461314142262400175360ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the permissive types. * * @author Richard Haines richard_c_haines@btinternet.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" /************ TYPEBOUNDS *************/ int qpol_typebounds_get_parent_name(const qpol_policy_t *policy, const qpol_typebounds_t * datum, const char **name) { type_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (type_datum_t *)datum; /* This will be zero if not a typebounds statement */ if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { *name = db->p_type_val_to_name[internal_datum->bounds - 1]; } return STATUS_SUCCESS; } int qpol_typebounds_get_child_name(const qpol_policy_t *policy, const qpol_typebounds_t * datum, const char **name) { type_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (type_datum_t *)datum; if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { *name = db->p_type_val_to_name[internal_datum->s.value - 1]; } return STATUS_SUCCESS; } static int hash_state_next_typebounds(qpol_iterator_t * iter) { void *datum = NULL; type_datum_t *internal_datum = NULL; do { hash_state_next(iter); if (qpol_iterator_end(iter)) break; qpol_iterator_get_item(iter, &datum); internal_datum = (type_datum_t *) datum; /* keep going on attributes */ if (internal_datum -> flavor != TYPE_TYPE) continue; /* keep going if type has no bounding */ } while (internal_datum->bounds == 0); return STATUS_SUCCESS; } int qpol_policy_get_typebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_types.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next_typebounds, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next_typebounds(*iter); /* since we are iterating over all types, ensure our first item is actually bounded. */ if (!qpol_iterator_end(*iter)) { void *datum = NULL; type_datum_t *internal_datum = NULL; qpol_iterator_get_item(*iter, &datum); internal_datum = (type_datum_t *) datum; if (internal_datum -> flavor != TYPE_TYPE || internal_datum->bounds == 0) hash_state_next_typebounds(*iter); } return STATUS_SUCCESS; } /************ ROLEBOUNDS *************/ int qpol_rolebounds_get_parent_name(const qpol_policy_t *policy, const qpol_rolebounds_t * datum, const char **name) { role_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (role_datum_t *)datum; /* This will be zero if not a rolebounds statement */ if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { *name = db->p_role_val_to_name[internal_datum->bounds - 1]; } return STATUS_SUCCESS; } int qpol_rolebounds_get_child_name(const qpol_policy_t *policy, const qpol_rolebounds_t * datum, const char **name) { role_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (role_datum_t *)datum; if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { *name = db->p_role_val_to_name[internal_datum->s.value - 1]; } return STATUS_SUCCESS; } /* As rolebounds are in roles use these, however will need to calc number of bounds manually in top.tcl*/ int qpol_policy_get_rolebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_roles.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } /************ USERBOUNDS *************/ int qpol_userbounds_get_parent_name(const qpol_policy_t *policy, const qpol_userbounds_t * datum, const char **name) { user_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (user_datum_t *)datum; /* This will be zero if not a userbounds statement */ if (internal_datum->bounds != 0) { *name = db->p_user_val_to_name[internal_datum->bounds - 1]; } return STATUS_SUCCESS; } int qpol_userbounds_get_child_name(const qpol_policy_t *policy, const qpol_userbounds_t * datum, const char **name) { user_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = NULL; /* The bounds rules started in ver 24 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (user_datum_t *)datum; if (internal_datum->bounds != 0) { *name = db->p_user_val_to_name[internal_datum->s.value - 1]; } return STATUS_SUCCESS; } /* As userbounds are in users use these, however will need to calc number of bounds manually in top.tcl*/ int qpol_policy_get_userbounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_users.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } setools-4.1.1/libqpol/class_perm_query.c000066400000000000000000000407121314142262400203730ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over * classes, commons, and permissions. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include "iterator_internal.h" #include #include "qpol_internal.h" /* perms */ typedef struct perm_hash_state { unsigned int bucket; hashtab_node_t *node; hashtab_t *table; const char *perm_name; } perm_hash_state_t; static int hash_state_next_class_w_perm(qpol_iterator_t * iter) { class_datum_t *internal_class = NULL; qpol_iterator_t *internal_perms = NULL; unsigned char has_perm = 0; perm_hash_state_t *hs = NULL; sepol_policydb_t sp; qpol_policy_t qp; char *tmp = NULL; const policydb_t *p; hs = (perm_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } /* shallow copy ok here as only internal values are used */ p = qpol_iterator_policy(iter); if (p == NULL) { errno = EINVAL; return STATUS_ERR; } sp.p = *p; qp.p = &sp; qp.fn = NULL; do { hash_state_next(iter); if (hash_state_end(iter)) break; internal_class = hs->node ? (class_datum_t *) hs->node->datum : NULL; qpol_class_get_perm_iter(&qp, (qpol_class_t *) internal_class, &internal_perms); for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) { qpol_iterator_get_item(internal_perms, (void **)&tmp); if (!strcmp(tmp, hs->perm_name)) { has_perm = 1; break; } } qpol_iterator_destroy(&internal_perms); } while (!has_perm && !hash_state_end(iter)); return STATUS_SUCCESS; } static size_t hash_perm_state_size_common(const qpol_iterator_t * iter) { perm_hash_state_t *hs = NULL; uint32_t tmp_bucket = 0; size_t count = 0; hashtab_node_t *tmp_node; sepol_policydb_t sp; qpol_policy_t qp; qpol_iterator_t *internal_perms; common_datum_t *internal_common; char *tmp = NULL; const policydb_t *p; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (perm_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } /* shallow copy ok here as only internal values are used */ p = qpol_iterator_policy(iter); if (p == NULL) { errno = EINVAL; return STATUS_ERR; } sp.p = *p; qp.p = &sp; qp.fn = NULL; for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { internal_common = tmp_node ? ((common_datum_t *) tmp_node->datum) : NULL; qpol_common_get_perm_iter(&qp, (qpol_common_t *) internal_common, &internal_perms); for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) { qpol_iterator_get_item(internal_perms, (void **)&tmp); if (!strcmp(tmp, hs->perm_name)) { count++; break; } } qpol_iterator_destroy(&internal_perms); } } return count; } static size_t hash_perm_state_size_class(const qpol_iterator_t * iter) { perm_hash_state_t *hs = NULL; uint32_t tmp_bucket = 0; size_t count = 0; hashtab_node_t *tmp_node; sepol_policydb_t sp; qpol_policy_t qp; qpol_iterator_t *internal_perms; class_datum_t *internal_class; char *tmp = NULL; const policydb_t *p; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (perm_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } /* shallow copy ok here as only internal values are used */ p = qpol_iterator_policy(iter); if (p == NULL) { errno = EINVAL; return STATUS_ERR; } sp.p = *p; qp.p = &sp; qp.fn = NULL; for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { internal_class = tmp_node ? ((class_datum_t *) tmp_node->datum) : NULL; qpol_class_get_perm_iter(&qp, (qpol_class_t *) internal_class, &internal_perms); for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) { qpol_iterator_get_item(internal_perms, (void **)&tmp); if (!strcmp(tmp, hs->perm_name)) { count++; break; } } qpol_iterator_destroy(&internal_perms); } } return count; } static int hash_state_next_common_w_perm(qpol_iterator_t * iter) { common_datum_t *internal_common = NULL; qpol_iterator_t *internal_perms = NULL; unsigned char has_perm = 0; perm_hash_state_t *hs = NULL; sepol_policydb_t sp; qpol_policy_t qp; char *tmp = NULL; const policydb_t *p; hs = (perm_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } /* shallow copy ok here as only internal values are used */ p = qpol_iterator_policy(iter); if (p == NULL) { errno = EINVAL; return STATUS_ERR; } sp.p = *p; qp.p = &sp; qp.fn = NULL; do { hash_state_next(iter); if (hash_state_end(iter)) break; internal_common = hs->node ? (common_datum_t *) hs->node->datum : NULL; qpol_common_get_perm_iter(&qp, (qpol_common_t *) internal_common, &internal_perms); for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) { qpol_iterator_get_item(internal_perms, (void **)&tmp); if (!strcmp(tmp, hs->perm_name)) { has_perm = 1; break; } } qpol_iterator_destroy(&internal_perms); } while (!has_perm && !hash_state_end(iter)); return STATUS_SUCCESS; } static int qpol_class_has_perm(const qpol_policy_t * p, const qpol_class_t * class, const char *perm) { qpol_iterator_t *iter = NULL; char *tmp; qpol_class_get_perm_iter(p, class, &iter); for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { qpol_iterator_get_item(iter, (void **)&tmp); if (!strcmp(perm, tmp)) { qpol_iterator_destroy(&iter); return 1; } } qpol_iterator_destroy(&iter); return 0; } static int qpol_common_has_perm(const qpol_policy_t * p, const qpol_common_t * common, const char *perm) { qpol_iterator_t *iter = NULL; char *tmp; qpol_common_get_perm_iter(p, common, &iter); for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { qpol_iterator_get_item(iter, (void **)&tmp); if (!strcmp(perm, tmp)) { qpol_iterator_destroy(&iter); return 1; } } qpol_iterator_destroy(&iter); return 0; } int qpol_perm_get_class_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** classes) { policydb_t *db; int error = 0; perm_hash_state_t *hs = NULL; if (policy == NULL || classes == NULL) { if (classes != NULL) *classes = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(perm_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_classes.table; hs->node = (*(hs->table))->htable[0]; hs->perm_name = perm; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next_class_w_perm, hash_state_end, hash_perm_state_size_class, free, classes)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || !qpol_class_has_perm(policy, (qpol_class_t *) hs->node->datum, perm)) hash_state_next_class_w_perm(*classes); return STATUS_SUCCESS; } int qpol_perm_get_common_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** commons) { policydb_t *db; int error = 0; perm_hash_state_t *hs = NULL; if (policy == NULL || commons == NULL) { if (commons != NULL) *commons = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(perm_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_commons.table; hs->node = (*(hs->table))->htable[0]; hs->perm_name = perm; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next_common_w_perm, hash_state_end, hash_perm_state_size_common, free, commons)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || !qpol_common_has_perm(policy, (qpol_common_t *) hs->node->datum, perm)) hash_state_next_common_w_perm(*commons); return STATUS_SUCCESS; } /* classes */ int qpol_policy_get_class_by_name(const qpol_policy_t * policy, const char *name, const qpol_class_t ** obj_class) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || obj_class == NULL) { if (obj_class != NULL) *obj_class = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_classes.table, (hashtab_key_t)name); if (internal_datum == NULL) { *obj_class = NULL; ERR(policy, "could not find class %s", name); errno = EINVAL; return STATUS_ERR; } *obj_class = (qpol_class_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_class_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_classes.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_class_get_value(const qpol_policy_t * policy, const qpol_class_t * obj_class, uint32_t * value) { class_datum_t *internal_datum; if (policy == NULL || obj_class == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (class_datum_t *) obj_class; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_class_get_common(const qpol_policy_t * policy, const qpol_class_t * obj_class, const qpol_common_t ** common) { class_datum_t *internal_datum = NULL; if (policy == NULL || obj_class == NULL || common == NULL) { if (common != NULL) *common = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (class_datum_t *) obj_class; *common = (qpol_common_t *) internal_datum->comdatum; return STATUS_SUCCESS; } int qpol_class_get_perm_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** perms) { class_datum_t *internal_datum = NULL; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || obj_class == NULL || perms == NULL) { if (perms != NULL) *perms = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (class_datum_t *) obj_class; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &internal_datum->permissions.table; if (hs->table && *(hs->table)) { hs->node = (*(hs->table))->htable[0]; } else { /* object class has no permissions */ hs->node = NULL; } if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_key, hash_state_next, hash_state_end, hash_state_size, free, perms)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*perms); return STATUS_SUCCESS; } int qpol_class_get_name(const qpol_policy_t * policy, const qpol_class_t * obj_class, const char **name) { class_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || obj_class == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (class_datum_t *) obj_class; *name = db->p_class_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } /* commons */ int qpol_policy_get_common_by_name(const qpol_policy_t * policy, const char *name, const qpol_common_t ** common) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || common == NULL) { if (common != NULL) *common = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_commons.table, (hashtab_key_t)name); if (internal_datum == NULL) { *common = NULL; ERR(policy, "could not find common %s", name); errno = EINVAL; return STATUS_ERR; } *common = (qpol_common_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_common_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_commons.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_common_get_value(const qpol_policy_t * policy, const qpol_common_t * common, uint32_t * value) { common_datum_t *internal_datum; if (policy == NULL || common == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (common_datum_t *) common; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_common_get_perm_iter(const qpol_policy_t * policy, const qpol_common_t * common, qpol_iterator_t ** perms) { common_datum_t *internal_datum = NULL; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || common == NULL || perms == NULL) { if (perms != NULL) *perms = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (common_datum_t *) common; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &internal_datum->permissions.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_key, hash_state_next, hash_state_end, hash_state_size, free, perms)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*perms); return STATUS_SUCCESS; } int qpol_common_get_name(const qpol_policy_t * policy, const qpol_common_t * common, const char **name) { common_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || common == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (common_datum_t *) common; *name = db->p_common_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } setools-4.1.1/libqpol/cond_query.c000066400000000000000000000323441314142262400171700ustar00rootroot00000000000000/** * @file * Implememtation for the public interface for searching and iterating * conditionals * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include "iterator_internal.h" #include "qpol_internal.h" #include #include #include typedef struct cond_state { cond_node_t *head; cond_node_t *cur; } cond_state_t; static int cond_state_end(const qpol_iterator_t * iter) { cond_state_t *cs = NULL; if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return cs->cur ? 0 : 1; } static void *cond_state_get_cur(const qpol_iterator_t * iter) { cond_state_t *cs = NULL; if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return cs->cur; } static int cond_state_next(qpol_iterator_t * iter) { cond_state_t *cs = NULL; if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } cs->cur = cs->cur->next; return STATUS_SUCCESS; } static size_t cond_state_size(const qpol_iterator_t * iter) { cond_state_t *cs = NULL; cond_node_t *tmp = NULL; size_t count = 0; if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } for (tmp = cs->head; tmp; tmp = tmp->next) count++; return count; } int qpol_policy_get_cond_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { int error = 0; cond_state_t *cs = NULL; policydb_t *db = NULL; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) { ERR(policy, "%s", "Cannot get conditionals: Rules not loaded"); errno = ENOTSUP; return STATUS_ERR; } db = &policy->p->p; if (!(cs = calloc(1, sizeof(cond_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } cs->head = cs->cur = db->cond_list; if (qpol_iterator_create(policy, (void *)cs, cond_state_get_cur, cond_state_next, cond_state_end, cond_state_size, free, iter)) { error = errno; goto err; } return STATUS_SUCCESS; err: free(cs); errno = error; return STATUS_ERR; } typedef struct cond_expr_state { cond_expr_t *head; cond_expr_t *cur; } cond_expr_state_t; static int cond_expr_state_end(const qpol_iterator_t * iter) { cond_expr_state_t *ces = NULL; if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ces->cur ? 0 : 1; } static void *cond_expr_state_get_cur(const qpol_iterator_t * iter) { cond_expr_state_t *ces = NULL; if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return ces->cur; } static int cond_expr_state_next(qpol_iterator_t * iter) { cond_expr_state_t *ces = NULL; if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ces->cur = ces->cur->next; return STATUS_SUCCESS; } static size_t cond_expr_state_size(const qpol_iterator_t * iter) { cond_expr_state_t *ces = NULL; cond_expr_t *tmp = NULL; size_t count = 0; if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } for (tmp = ces->head; tmp; tmp = tmp->next) count++; return count; } int qpol_cond_get_expr_node_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, qpol_iterator_t ** iter) { int error = 0; cond_expr_state_t *ces = NULL; cond_node_t *internal_cond = NULL; if (iter) *iter = NULL; if (!policy || !cond || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if (!(ces = calloc(1, sizeof(cond_expr_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } ces->head = ces->cur = internal_cond->expr; if (qpol_iterator_create(policy, (void *)ces, cond_expr_state_get_cur, cond_expr_state_next, cond_expr_state_end, cond_expr_state_size, free, iter)) { error = errno; goto err; } return STATUS_SUCCESS; err: free(ces); errno = error; return STATUS_ERR; } typedef struct cond_rule_state { cond_av_list_t *head; cond_av_list_t *cur; uint32_t rule_type_mask; } cond_rule_state_t; static int cond_rule_state_end(const qpol_iterator_t * iter) { cond_rule_state_t *crs = NULL; if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return crs->cur ? 0 : 1; } static void *cond_rule_state_get_cur(const qpol_iterator_t * iter) { cond_rule_state_t *crs = NULL; if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return crs->cur->node; } static int cond_rule_state_next(qpol_iterator_t * iter) { cond_rule_state_t *crs = NULL; if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } do { crs->cur = crs->cur->next; } while (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask)); return STATUS_SUCCESS; } static size_t cond_rule_state_size(const qpol_iterator_t * iter) { cond_rule_state_t *crs = NULL; cond_av_list_t *tmp = NULL; size_t count = 0; if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } for (tmp = crs->head; tmp; tmp = tmp->next) { if (tmp->node->key.specified & crs->rule_type_mask) count++; } return count; } int qpol_cond_get_av_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter) { int error = 0; cond_rule_state_t *crs = NULL; cond_node_t *internal_cond = NULL; if (iter) *iter = NULL; if (!policy || !cond || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (rule_type_mask & ~(QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } crs->head = crs->cur = internal_cond->true_list; crs->rule_type_mask = rule_type_mask; if (qpol_iterator_create(policy, (void *)crs, cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end, cond_rule_state_size, free, iter)) { error = errno; goto err; } if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask)) qpol_iterator_next(*iter); return STATUS_SUCCESS; err: free(crs); errno = error; return STATUS_ERR; } int qpol_cond_get_te_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter) { int error = 0; cond_rule_state_t *crs = NULL; cond_node_t *internal_cond = NULL; if (iter) *iter = NULL; if (!policy || !cond || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (rule_type_mask & ~(QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } crs->head = crs->cur = internal_cond->true_list; crs->rule_type_mask = rule_type_mask; if (qpol_iterator_create(policy, (void *)crs, cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end, cond_rule_state_size, free, iter)) { error = errno; goto err; } if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask)) qpol_iterator_next(*iter); return STATUS_SUCCESS; err: free(crs); errno = error; return STATUS_ERR; } int qpol_cond_get_av_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter) { int error = 0; cond_rule_state_t *crs = NULL; cond_node_t *internal_cond = NULL; if (iter) *iter = NULL; if (!policy || !cond || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (rule_type_mask & ~(QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } crs->head = crs->cur = internal_cond->false_list; crs->rule_type_mask = rule_type_mask; if (qpol_iterator_create(policy, (void *)crs, cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end, cond_rule_state_size, free, iter)) { error = errno; goto err; } if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask)) qpol_iterator_next(*iter); return STATUS_SUCCESS; err: free(crs); errno = error; return STATUS_ERR; } int qpol_cond_get_te_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter) { int error = 0; cond_rule_state_t *crs = NULL; cond_node_t *internal_cond = NULL; if (iter) *iter = NULL; if (!policy || !cond || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (rule_type_mask & ~(QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } crs->head = crs->cur = internal_cond->false_list; crs->rule_type_mask = rule_type_mask; if (qpol_iterator_create(policy, (void *)crs, cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end, cond_rule_state_size, free, iter)) { error = errno; goto err; } if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask)) qpol_iterator_next(*iter); return STATUS_SUCCESS; err: free(crs); errno = error; return STATUS_ERR; } int qpol_cond_eval(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t * is_true) { int error = 0; cond_node_t *internal_cond = NULL; if (is_true) *is_true = 0; if (!policy || !cond || !is_true) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_node_t *) cond; if ((*is_true = (uint32_t) cond_evaluate_expr(&policy->p->p, internal_cond->expr)) > 1) { error = ERANGE; goto err; } return STATUS_SUCCESS; err: ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } int qpol_cond_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, uint32_t * expr_type) { cond_expr_t *internal_cond = NULL; if (expr_type) *expr_type = 0; if (!policy || !node || !expr_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cond = (cond_expr_t *) node; *expr_type = internal_cond->expr_type; return STATUS_SUCCESS; } int qpol_cond_expr_node_get_bool(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, qpol_bool_t ** cond_bool) { int error = 0; cond_expr_t *internal_cond = NULL; policydb_t *db = NULL; if (cond_bool) *cond_bool = NULL; if (!policy || !node || !cond_bool) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_cond = (cond_expr_t *) node; if (internal_cond->expr_type != QPOL_COND_EXPR_BOOL) { error = EINVAL; goto err; } if (!(*cond_bool = (qpol_bool_t *) db->bool_val_to_struct[internal_cond->bool - 1])) { error = EINVAL; goto err; } return STATUS_SUCCESS; err: ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } setools-4.1.1/libqpol/config.h000066400000000000000000000133211314142262400162640ustar00rootroot00000000000000/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ /* #undef AC_APPLE_UNIVERSAL_BUILD */ /* GTK+ is version 2.8+ */ #define GTK_2_8 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `sepol' library (-lsepol). */ #define HAVE_LIBSEPOL 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `rand_r' function. */ #define HAVE_RAND_R 1 /* sepol's new expand boolmap behavior */ #define HAVE_SEPOL_BOOLMAP 1 /* if bounds rules are present */ #define HAVE_SEPOL_BOUNDARY 1 /* if source policy types/attributes are present */ #define HAVE_SEPOL_CONSTRAINT_NAMES 1 /* if default_user rule present */ #define HAVE_SEPOL_DEFAULT_TYPE 1 /* if libsepol has errcodes.h */ #define HAVE_SEPOL_ERRCODES 1 /* if the filename transition rule present */ #define HAVE_SEPOL_FILENAME_TRANS 1 /* if default_user/role/range rules are present */ #define HAVE_SEPOL_NEW_OBJECT_DEFAULTS 1 /* if types can be marked as permissive */ #define HAVE_SEPOL_PERMISSIVE_TYPES 1 /* if libsepol has policycaps */ #define HAVE_SEPOL_POLICYCAPS 1 /* if role attributes are supported */ #define HAVE_SEPOL_ROLE_ATTRS 1 /* if users and roles are mapped during policy expansion */ #define HAVE_SEPOL_USER_ROLE_MAPPING 1 /* if source policy Xen devicetreecon and iomemcon 64bit are present */ #define HAVE_SEPOL_XEN_DEVICETREE 1 /* OR */ /* #undef HAVE_SEPOL_XEN_DEVICETREE */ /* if source policy ioctl white listing */ #define HAVE_SEPOL_XPERM_IOCTL 1 /* Define to 1 if stdbool.h conforms to C99. */ #define HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if the system has the type `_Bool'. */ #define HAVE__BOOL 1 /* libapol version */ #define LIBAPOL_VERSION_STRING "4.4" /* libpoldiff version */ #define LIBPOLDIFF_VERSION_STRING "1.3.3" /* libqpol version */ #define LIBQPOL_VERSION_STRING "1.7" /* libapol version */ #define LIBSEAUDIT_VERSION_STRING "4.5" /* libsefs version */ #define LIBSEFS_VERSION_STRING "4.0.4" /* link programs using shared libraries */ #define LINK_SHARED 1 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Are we building against Mac OS X TkAqua? */ /* #undef MAC_OSX_TK */ /* disable calls to assert() */ #define NDEBUG 1 /* Name of package */ #define PACKAGE "setools" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "Tresys Technology " /* Define to the full name of this package. */ #define PACKAGE_NAME "setools" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "setools 3.3.8" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "setools" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.3.8" /* if avtab sizes are calculated dynamically by loader or are hardcoded */ #define SEPOL_DYNAMIC_AVTAB 1 /* remap of libsepol 1.x.x define to 2.x.x */ /* #undef SEPOL_EEXIST */ /* remap of libsepol 1.x.x define to 2.x.x */ /* #undef SEPOL_ENOMEM */ /* maximum policy version supported by libsepol */ #define SEPOL_POLICY_VERSION_MAX 29 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* location of testing policies */ #define TEST_POLICIES "." /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "3.3.8" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #define YYTEXT_POINTER 1 /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ setools-4.1.1/libqpol/constraint_query.c000066400000000000000000000566111314142262400204340ustar00rootroot00000000000000/** * @file * Implementation of the public interface for searching and iterating over * constraints * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" #include #include #include #include #include struct qpol_constraint { const qpol_class_t *obj_class; constraint_node_t *constr; }; typedef struct policy_constr_state { qpol_iterator_t *class_iter; qpol_iterator_t *constr_iter; const qpol_policy_t *policy; /* needed to get sub iterators */ } policy_constr_state_t; static int policy_constr_state_end(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return (qpol_iterator_end(pcs->class_iter) && qpol_iterator_end(pcs->constr_iter)) ? 1 : 0; } static void *policy_constr_state_get_cur(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; void *tmp = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } if (qpol_iterator_get_item(pcs->constr_iter, &tmp)) { return NULL; } return tmp; } static int policy_constr_state_next(qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } qpol_iterator_next(pcs->constr_iter); while (qpol_iterator_end(pcs->constr_iter)) { qpol_iterator_destroy(&pcs->constr_iter); qpol_iterator_next(pcs->class_iter); if (qpol_iterator_end(pcs->class_iter)) return STATUS_SUCCESS; if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class)) return STATUS_ERR; if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &pcs->constr_iter)) return STATUS_ERR; } return STATUS_SUCCESS; } static size_t policy_constr_state_size(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL; size_t count = 0, tmp = 0; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } if (qpol_policy_get_class_iter(pcs->policy, &internal_iter)) return 0; for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) { if (qpol_iterator_get_item(internal_iter, (void **)&obj_class)) goto err; if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &constr_iter)) goto err; if (qpol_iterator_get_size(constr_iter, &tmp)) goto err; count += tmp; tmp = 0; qpol_iterator_destroy(&constr_iter); } qpol_iterator_destroy(&internal_iter); return count; err: qpol_iterator_destroy(&internal_iter); qpol_iterator_destroy(&constr_iter); return 0; } static void policy_constr_state_free(void *x) { policy_constr_state_t *pcs = (policy_constr_state_t *) x; if (!pcs) return; qpol_iterator_destroy(&pcs->class_iter); qpol_iterator_destroy(&pcs->constr_iter); free(pcs); } int qpol_policy_get_constraint_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policy_constr_state_t *pcs = NULL; int error = 0; qpol_class_t *tmp = NULL; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } pcs->policy = policy; if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) { error = errno; goto err; } if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) { error = errno; ERR(policy, "Error getting first class: %s", strerror(error)); goto err; } if (qpol_class_get_constraint_iter(policy, tmp, &pcs->constr_iter)) { error = errno; goto err; } if (qpol_iterator_create(policy, (void *)pcs, policy_constr_state_get_cur, policy_constr_state_next, policy_constr_state_end, policy_constr_state_size, policy_constr_state_free, iter)) { error = errno; goto err; } if (qpol_iterator_end(pcs->constr_iter)) { if (qpol_iterator_next(*iter)) { error = errno; pcs = NULL; /* avoid double free, iterator will destroy this */ ERR(policy, "Error finding first constraint: %s", strerror(error)); goto err; } } return STATUS_SUCCESS; err: policy_constr_state_free(pcs); qpol_iterator_destroy(iter); errno = error; return STATUS_ERR; } int qpol_constraint_get_class(const qpol_policy_t * policy, const qpol_constraint_t * constr, const qpol_class_t ** obj_class) { if (obj_class) *obj_class = NULL; if (!policy || !constr || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *obj_class = constr->obj_class; return STATUS_SUCCESS; } int qpol_constraint_get_perm_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter) { perm_state_t *ps = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !constr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) constr->constr; if (!(ps = calloc(1, sizeof(perm_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; } ps->perm_set = internal_constr->permissions; qpol_class_get_value(policy, constr->obj_class, &ps->obj_class_val); if (qpol_iterator_create(policy, (void *)ps, perm_state_get_cur, perm_state_next, perm_state_end, perm_state_size, free, iter)) { free(ps); return STATUS_ERR; } if (!(ps->perm_set & 1)) /* defaults to bit 0 */ qpol_iterator_next(*iter); return STATUS_SUCCESS; } typedef struct constr_expr_state { constraint_expr_t *head; constraint_expr_t *cur; } constr_expr_state_t; static int constr_expr_state_end(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ces->cur ? 0 : 1; } static void *constr_expr_state_get_cur(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return ces->cur; } static int constr_expr_state_next(qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ces->cur = ces->cur->next; return STATUS_SUCCESS; } static size_t constr_expr_state_size(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; constraint_expr_t *tmp = NULL; size_t count = 0; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } for (tmp = ces->head; tmp; tmp = tmp->next) count++; return count; } int qpol_constraint_get_expr_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter) { constr_expr_state_t *ces = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !constr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) constr->constr; if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } ces->head = ces->cur = internal_constr->expr; if (qpol_iterator_create(policy, (void *)ces, constr_expr_state_get_cur, constr_expr_state_next, constr_expr_state_end, constr_expr_state_size, free, iter)) { free(ces); return STATUS_ERR; } return STATUS_SUCCESS; } static int policy_constr_state_next_vtrans(qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } qpol_iterator_next(pcs->constr_iter); while (qpol_iterator_end(pcs->constr_iter)) { qpol_iterator_destroy(&pcs->constr_iter); qpol_iterator_next(pcs->class_iter); if (qpol_iterator_end(pcs->class_iter)) return STATUS_SUCCESS; if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class)) return STATUS_ERR; if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &pcs->constr_iter)) return STATUS_ERR; } return STATUS_SUCCESS; } static size_t policy_constr_state_size_vtrans(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL; size_t count = 0, tmp = 0; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } if (qpol_policy_get_class_iter(pcs->policy, &internal_iter)) return 0; for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) { if (qpol_iterator_get_item(internal_iter, (void **)&obj_class)) goto err; if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &constr_iter)) goto err; if (qpol_iterator_get_size(constr_iter, &tmp)) goto err; count += tmp; tmp = 0; qpol_iterator_destroy(&constr_iter); } qpol_iterator_destroy(&internal_iter); return count; err: qpol_iterator_destroy(&internal_iter); qpol_iterator_destroy(&constr_iter); return 0; } int qpol_policy_get_validatetrans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policy_constr_state_t *pcs = NULL; int error = 0; qpol_class_t *tmp = NULL; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } pcs->policy = policy; if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) { error = errno; goto err; } if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) { error = errno; ERR(policy, "Error getting first class: %s", strerror(error)); goto err; } if (qpol_class_get_validatetrans_iter(policy, tmp, &pcs->constr_iter)) { error = errno; goto err; } if (qpol_iterator_create(policy, (void *)pcs, policy_constr_state_get_cur, policy_constr_state_next_vtrans, policy_constr_state_end, policy_constr_state_size_vtrans, policy_constr_state_free, iter)) { error = errno; goto err; } if (qpol_iterator_end(pcs->constr_iter)) { if (qpol_iterator_next(*iter)) { error = errno; pcs = NULL; /* avoid double free, iterator will destroy this */ ERR(policy, "Error finding first validatetrans: %s", strerror(error)); goto err; } } return STATUS_SUCCESS; err: policy_constr_state_free(pcs); qpol_iterator_destroy(iter); errno = error; return STATUS_ERR; } int qpol_validatetrans_get_class(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, const qpol_class_t ** obj_class) { if (obj_class) *obj_class = NULL; if (!policy || !vtrans || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *obj_class = ((qpol_constraint_t *) vtrans)->obj_class; return STATUS_SUCCESS; } int qpol_validatetrans_get_expr_iter(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, qpol_iterator_t ** iter) { constr_expr_state_t *ces = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !vtrans || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) ((qpol_constraint_t *) vtrans)->constr; if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } ces->head = ces->cur = internal_constr->expr; if (qpol_iterator_create(policy, (void *)ces, constr_expr_state_get_cur, constr_expr_state_next, constr_expr_state_end, constr_expr_state_size, free, iter)) { free(ces); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * expr_type) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !expr_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *expr_type = internal_expr->expr_type; return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_sym_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * sym_type) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !sym_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *sym_type = internal_expr->attr; return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_op(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * op) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !op) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *op = internal_expr->op; return STATUS_SUCCESS; } typedef struct cexpr_name_state { ebitmap_t *inc; ebitmap_t *sub; size_t cur; #define QPOL_CEXPR_NAME_STATE_INC_LIST 0 #define QPOL_CEXPR_NAME_STATE_SUB_LIST 1 unsigned char list; } cexpr_name_state_t; static int cexpr_name_state_end(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (cns->list == QPOL_CEXPR_NAME_STATE_SUB_LIST && (cns->sub ? cns->cur >= cns->sub->highbit : 1)) return 1; return 0; } static int cexpr_name_state_next(qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; ebitmap_t *bmap = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } bmap = (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST ? cns->inc : cns->sub); do { cns->cur++; if (cns->cur >= bmap->highbit) { if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST) { cns->list = QPOL_CEXPR_NAME_STATE_SUB_LIST; cns->cur = 0; bmap = cns->sub; if (!bmap) break; } else { break; } } } while (!ebitmap_get_bit(bmap, cns->cur)); return STATUS_SUCCESS; } static size_t cexpr_name_state_size(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; size_t count = 0, bit = 0; ebitmap_node_t *node = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } ebitmap_for_each_bit(cns->inc, node, bit) { count += ebitmap_get_bit(cns->inc, bit); } if (!(cns->sub)) return count; bit = 0; ebitmap_for_each_bit(cns->sub, node, bit) { count += ebitmap_get_bit(cns->sub, bit); } return count; } static void *cexpr_name_state_get_cur_user(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return strdup(db->p_user_val_to_name[cns->cur]); } static void *cexpr_name_state_get_cur_role(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return strdup(db->p_role_val_to_name[cns->cur]); } static void *cexpr_name_state_get_cur_type(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; char *tmp = NULL, *name = NULL; size_t len = 0; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } tmp = strdup(db->p_type_val_to_name[cns->cur]); if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST) return tmp; len = strlen(tmp); name = calloc(len + 2, sizeof(char)); if (!name) { free(tmp); errno = ENOMEM; return NULL; } len++; snprintf(name, len + 1, "-%s", tmp); free(tmp); return name; } int qpol_constraint_expr_node_get_names_iter(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, qpol_iterator_t ** iter) { constraint_expr_t *internal_expr = NULL; cexpr_name_state_t *cns = NULL; int policy_type = 0; if (iter) *iter = NULL; if (!policy || !expr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (qpol_policy_get_type(policy, &policy_type)) return STATUS_ERR; internal_expr = (constraint_expr_t *) expr; if (internal_expr->expr_type != QPOL_CEXPR_TYPE_NAMES) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(cns = calloc(1, sizeof(cexpr_name_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } unsigned int policy_version; if (qpol_policy_get_policy_version(policy, &policy_version)) return STATUS_ERR; if (internal_expr->attr & QPOL_CEXPR_SYM_TYPE) { if (policy_type == QPOL_POLICY_KERNEL_BINARY && policy_version <= 28) { cns->inc = &(internal_expr->names); } else if (policy_type == QPOL_POLICY_KERNEL_BINARY && policy_version > 28) { cns->inc = &(internal_expr->type_names->types); } else { cns->inc = &(internal_expr->type_names->types); cns->sub = &(internal_expr->type_names->negset); } } else { cns->inc = &(internal_expr->names); } cns->list = QPOL_CEXPR_NAME_STATE_INC_LIST; cns->cur = cns->inc->node ? cns->inc->node->startbit : 0; switch (internal_expr->attr & ~(QPOL_CEXPR_SYM_TARGET | QPOL_CEXPR_SYM_XTARGET)) { case QPOL_CEXPR_SYM_USER: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_user, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } case QPOL_CEXPR_SYM_ROLE: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_role, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } case QPOL_CEXPR_SYM_TYPE: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_type, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } default: { ERR(policy, "%s", strerror(EINVAL)); free(cns); errno = EINVAL; return STATUS_ERR; } } if (cns->inc->node && !ebitmap_get_bit(cns->inc, cns->cur)) qpol_iterator_next(*iter); return STATUS_SUCCESS; } typedef struct class_constr_state { constraint_node_t *head; constraint_node_t *cur; const qpol_class_t *obj_class; } class_constr_state_t; static int class_constr_state_end(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ccs->cur ? 0 : 1; } static void *class_constr_state_get_cur(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; qpol_constraint_t *qc = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } if (!(qc = calloc(1, sizeof(qpol_constraint_t)))) { return NULL; /* errno set by calloc */ } qc->obj_class = ccs->obj_class; qc->constr = ccs->cur; return qc; } static int class_constr_state_next(qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ccs->cur = ccs->cur->next; return STATUS_SUCCESS; } static size_t class_constr_state_size(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; constraint_node_t *tmp = NULL; size_t count = 0; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return 0; } for (tmp = ccs->head; tmp; tmp = tmp->next) count++; return count; } int qpol_class_get_constraint_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** constr) { class_constr_state_t *ccs = NULL; class_datum_t *internal_class = NULL; int error = 0; if (constr) *constr = NULL; if (!policy || !obj_class || !constr) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_class = (class_datum_t *) obj_class; ccs = calloc(1, sizeof(class_constr_state_t)); if (!ccs) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } ccs->obj_class = obj_class; ccs->head = ccs->cur = internal_class->constraints; if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur, class_constr_state_next, class_constr_state_end, class_constr_state_size, free, constr)) { return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_class_get_validatetrans_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** vtrans) { class_constr_state_t *ccs = NULL; class_datum_t *internal_class = NULL; int error = 0; if (vtrans) *vtrans = NULL; if (!policy || !obj_class || !vtrans) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_class = (class_datum_t *) obj_class; ccs = calloc(1, sizeof(class_constr_state_t)); if (!ccs) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } ccs->obj_class = obj_class; ccs->head = ccs->cur = internal_class->validatetrans; if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur, class_constr_state_next, class_constr_state_end, class_constr_state_size, free, vtrans)) { return STATUS_ERR; } return STATUS_SUCCESS; } setools-4.1.1/libqpol/context_query.c000066400000000000000000000066701314142262400177340ustar00rootroot00000000000000/** * @file * Defines the public interface for accessing contexts. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include #include #include #include "qpol_internal.h" int qpol_context_get_user(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_user_t ** user) { policydb_t *db = NULL; context_struct_t *internal_context = NULL; if (user != NULL) *user = NULL; if (policy == NULL || context == NULL || user == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_context = (context_struct_t *) context; db = &policy->p->p; *user = (qpol_user_t *) db->user_val_to_struct[internal_context->user - 1]; return STATUS_SUCCESS; } int qpol_context_get_role(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_role_t ** role) { policydb_t *db = NULL; context_struct_t *internal_context = NULL; if (role != NULL) *role = NULL; if (policy == NULL || context == NULL || role == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_context = (context_struct_t *) context; db = &policy->p->p; *role = (qpol_role_t *) db->role_val_to_struct[internal_context->role - 1]; return STATUS_SUCCESS; } int qpol_context_get_type(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_type_t ** type) { policydb_t *db = NULL; context_struct_t *internal_context = NULL; if (type != NULL) *type = NULL; if (policy == NULL || context == NULL || type == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_context = (context_struct_t *) context; db = &policy->p->p; *type = (qpol_type_t *) db->type_val_to_struct[internal_context->type - 1]; return STATUS_SUCCESS; } int qpol_context_get_range(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_mls_range_t ** range) { context_struct_t *internal_context = NULL; if (range != NULL) *range = NULL; if (policy == NULL || context == NULL || range == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!qpol_policy_has_capability(policy, QPOL_CAP_MLS)) { *range = NULL; } else { internal_context = (context_struct_t *) context; *range = (qpol_mls_range_t *) & internal_context->range; } return STATUS_SUCCESS; } setools-4.1.1/libqpol/default_object_query.c000066400000000000000000000165411314142262400212200ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over default objects. * * @author Richard Haines richard_c_haines@btinternet.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_default_object_get_class(const qpol_policy_t *policy, const qpol_default_object_t * datum, const qpol_class_t **cls) { class_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || cls == NULL) { if (cls != NULL) *cls = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *cls = NULL; internal_datum = (class_datum_t *)datum; /* These will be zero if no default_objects set */ if (internal_datum->default_user || internal_datum->default_role || internal_datum->default_type || internal_datum->default_range) { *cls = (const qpol_class_t *) datum; } return STATUS_SUCCESS; } int qpol_default_object_get_user_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) { class_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *value = NULL; /* The user default started in ver 27 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) return STATUS_SUCCESS; internal_datum = (class_datum_t *)datum; if (internal_datum->default_user == DEFAULT_SOURCE) { *value = "source"; } else if (internal_datum->default_user == DEFAULT_TARGET) { *value = "target"; } return STATUS_SUCCESS; } int qpol_default_object_get_role_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) { class_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *value = NULL; /* The role default started in ver 27 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) return STATUS_SUCCESS; internal_datum = (class_datum_t *)datum; if (internal_datum->default_role == DEFAULT_SOURCE) { *value = "source"; } else if (internal_datum->default_role == DEFAULT_TARGET) { *value = "target"; } return STATUS_SUCCESS; } int qpol_default_object_get_type_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) { class_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *value = NULL; /* The type default started in ver 28 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_TYPE)) return STATUS_SUCCESS; internal_datum = (class_datum_t *)datum; if (internal_datum->default_type == DEFAULT_SOURCE) { *value = "source"; } else if (internal_datum->default_type == DEFAULT_TARGET) { *value = "target"; } return STATUS_SUCCESS; } int qpol_default_object_get_range_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) { class_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *value = NULL; /* The range default started in ver 27 */ if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) return STATUS_SUCCESS; internal_datum = (class_datum_t *)datum; switch (internal_datum->default_range) { case DEFAULT_SOURCE_LOW: *value = "source low"; break; case DEFAULT_SOURCE_HIGH: *value = "source high"; break; case DEFAULT_SOURCE_LOW_HIGH: *value = "source low_high"; break; case DEFAULT_TARGET_LOW: *value = "target low"; break; case DEFAULT_TARGET_HIGH: *value = "target high"; break; case DEFAULT_TARGET_LOW_HIGH: *value = "target low_high"; break; default: break; } return STATUS_SUCCESS; } /* As default objects are in classes use these, however will need to calc number of default objects manually in top.tcl*/ int qpol_policy_get_default_object_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; /* class_datum_t *cladatum; sepol_security_class_t tclass; char *class; for (tclass = 1; tclass <= db->p_classes.nprim; tclass++) { cladatum = db->class_val_to_struct[tclass - 1]; class = db->p_class_val_to_name[tclass - 1]; if (cladatum->default_user == DEFAULT_SOURCE) { printf("default_user %s source;\n", class); } else if (cladatum->default_user == DEFAULT_TARGET) { printf("default_user %s target;\n", class); } if (cladatum->default_role == DEFAULT_SOURCE) { printf("default_role %s source;\n", class); } else if (cladatum->default_role == DEFAULT_TARGET) { printf("default_role %s target;\n", class); } if (cladatum->default_type == DEFAULT_SOURCE) { printf("default_type %s source;\n", class); } else if (cladatum->default_type == DEFAULT_TARGET) { printf("default_type %s target;\n", class); } switch (cladatum->default_range) { case DEFAULT_SOURCE_LOW: printf("default_range %s source low;\n", class); break; case DEFAULT_SOURCE_HIGH: printf("default_range %s source high;\n", class); break; case DEFAULT_SOURCE_LOW_HIGH: printf("default_range %s source low_high;\n", class); break; case DEFAULT_TARGET_LOW: printf("default_range %s target low;\n", class); break; case DEFAULT_TARGET_HIGH: printf("default_range %s target high;\n", class); break; case DEFAULT_TARGET_LOW_HIGH: printf("default_range %s target low_high;\n", class); break; default: break; } } */ hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_classes.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } setools-4.1.1/libqpol/expand.c000066400000000000000000000124001314142262400162660ustar00rootroot00000000000000/** * @file * * Provides a way for setools to expand policy. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "qpol_internal.h" #include "expand.h" static int expand_type_attr_map(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *ptr) { type_datum_t *type = NULL, *orig_type; policydb_t *db = (policydb_t *) ptr; ebitmap_node_t *node = NULL; uint32_t bit = 0; type = (type_datum_t *) datum; /* if this is an attribute go through its list * of types and put in reverse mappings */ if (type->flavor == TYPE_ATTRIB) { ebitmap_for_each_bit(&type->types, node, bit) { if (ebitmap_node_get_bit(node, bit)) { orig_type = db->type_val_to_struct[bit]; if (ebitmap_set_bit(&orig_type->types, type->s.value - 1, 1)) { return -1; } } } } return 0; } static int expand_type_permissive_map(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *ptr) { #ifdef HAVE_SEPOL_PERMISSIVE_TYPES type_datum_t *type = (type_datum_t *) datum; policydb_t *db = (policydb_t *) ptr; type = (type_datum_t *) datum; /* if this type is marked as permissive, then set its corresponding bit in the permissive map. note that unlike other bitmaps, this one does not subtract 1 in the bitmap. */ if (type->flags & TYPE_FLAGS_PERMISSIVE) { uint32_t value; if (type->flavor == TYPE_ALIAS) { /* aliases that came from modules should use the value * referenced to by that alias */ value = type->primary; } else { value = type->s.value; } if (ebitmap_set_bit(&db->permissive_map, value, 1)) { return -1; } } #endif return 0; } int qpol_expand_module(qpol_policy_t * base, int neverallows) { unsigned int i; uint32_t *typemap = NULL, *boolmap = NULL, *rolemap = NULL, *usermap = NULL; policydb_t *db; int rt, error = 0; INFO(base, "%s", "Expanding policy. (Step 3 of 5)"); if (base == NULL) { ERR(base, "%s", strerror(EINVAL)); errno = EINVAL; return -1; } db = &base->p->p; /* activate the global branch before expansion */ db->global->branch_list->enabled = 1; db->global->enabled = db->global->branch_list; /* expand out the types to include all the attributes */ if (hashtab_map(db->p_types.table, expand_type_attr_map, (db))) { error = errno; ERR(base, "%s", "Error expanding attributes for types."); goto err; } #ifdef HAVE_SEPOL_PERMISSIVE_TYPES /* fill in the permissive types bitmap. this is normally done * in type_copy_callback(), but types are not copied in * expand_module_avrules() */ if (hashtab_map(db->p_types.table, expand_type_permissive_map, (db))) { error = errno; ERR(base, "%s", "Error expanding attributes for types."); goto err; } #endif /* Build the typemap such that we can expand into the same policy */ typemap = (uint32_t *) calloc(db->p_types.nprim, sizeof(uint32_t)); if (typemap == NULL) { error = errno; ERR(base, "%s", strerror(errno)); goto err; } for (i = 0; i < db->p_types.nprim; i++) { typemap[i] = i + 1; } #ifdef HAVE_SEPOL_BOOLMAP boolmap = (uint32_t *) calloc(db->p_bools.nprim, sizeof(uint32_t)); if (boolmap == NULL) { error = errno; ERR(base, "%s", strerror(errno)); goto err; } for (i = 0; i < db->p_bools.nprim; i++) { boolmap[i] = i + 1; } #ifdef HAVE_SEPOL_USER_ROLE_MAPPING rolemap = (uint32_t *) calloc(db->p_roles.nprim, sizeof(uint32_t)); if (rolemap == NULL) { error = errno; ERR(base, "%s", strerror(errno)); goto err; } for (i = 0; i < db->p_roles.nprim; i++) { rolemap[i] = i + 1; } usermap = (uint32_t *) calloc(db->p_users.nprim, sizeof(uint32_t)); if (usermap == NULL) { error = errno; ERR(base, "%s", strerror(errno)); goto err; } for (i = 0; i < db->p_users.nprim; i++) { usermap[i] = i + 1; } rt = expand_module_avrules(base->sh, db, db, typemap, boolmap, rolemap, usermap, 0, neverallows); #else rt = expand_module_avrules(base->sh, db, db, typemap, boolmap, 0, neverallows); #endif // end of user/role mapping #else rt = expand_module_avrules(base->sh, db, db, typemap, 0, neverallows); #endif // end of boolean mapping if (rt < 0) { error = errno; goto err; } rt = 0; exit: free(typemap); free(boolmap); free(rolemap); free(usermap); errno = error; return rt; err: rt = -1; /* libsepol does not always set errno correctly, so have a default errno here */ if (!error) error = EIO; goto exit; } setools-4.1.1/libqpol/expand.h000066400000000000000000000026471314142262400163070ustar00rootroot00000000000000/** * @file * * Public interface for expanding a modular policy. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_EXPAND_H #define QPOL_EXPAND_H #ifdef __cplusplus extern "C" { #endif #include /** * Expand a policy. Linking should always be done prior to calling * this function. * * @param base the module to expand. * @param neverallows if non-zero expand neverallows. * @return 0 on success, -1 on error. */ int qpol_expand_module(qpol_policy_t * base, int neverallows); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/fs_use_query.c000066400000000000000000000101121314142262400175160ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over fs_use statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_policy_get_fs_use_by_name(const qpol_policy_t * policy, const char *name, const qpol_fs_use_t ** ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || name == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_FSUSE]; tmp; tmp = tmp->next) { if (!strcmp(name, tmp->u.name)) break; } *ocon = (qpol_fs_use_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find fs_use statement for %s", name); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_fs_use_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_FSUSE]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_fs_use_get_name(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const char **name) { ocontext_t *internal_ocon = NULL; if (name != NULL) *name = NULL; if (policy == NULL || ocon == NULL || name == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *name = internal_ocon->u.name; return STATUS_SUCCESS; } int qpol_fs_use_get_behavior(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, uint32_t * behavior) { ocontext_t *internal_ocon = NULL; if (behavior != NULL) *behavior = 0; if (policy == NULL || ocon == NULL || behavior == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *behavior = internal_ocon->v.behavior; return STATUS_SUCCESS; } int qpol_fs_use_get_context(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const qpol_context_t ** context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; if (internal_ocon->v.behavior == QPOL_FS_USE_PSID) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *context = (qpol_context_t *) & (internal_ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/libqpol/ftrule_query.c000066400000000000000000000155511314142262400175470ustar00rootroot00000000000000/** * @file * Defines public interface for iterating over filename transition rules. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include "iterator_internal.h" #include "qpol_internal.h" #include #include typedef struct filename_trans_state { unsigned int bucket; hashtab_ptr_t cur_item; filename_trans_t *cur; } filename_trans_state_t; static int filename_trans_state_end(const qpol_iterator_t * iter) { filename_trans_state_t *fts = NULL; if (!iter || !(fts = qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return fts->cur ? 0 : 1; } static void *filename_trans_state_get_cur(const qpol_iterator_t * iter) { filename_trans_state_t *fts = NULL; const policydb_t *db = NULL; if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || filename_trans_state_end(iter)) { errno = EINVAL; return NULL; } return fts->cur; } static int filename_trans_state_next(qpol_iterator_t * iter) { filename_trans_state_t *fts = NULL; const policydb_t *db = NULL; if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } if (filename_trans_state_end(iter)) { errno = ERANGE; return STATUS_ERR; } fts->cur_item = fts->cur_item->next; while (fts->cur_item == NULL) { fts->bucket++; if (fts->bucket >= db->filename_trans->size) { break; } fts->cur_item = db->filename_trans->htable[fts->bucket]; } if (fts->cur_item == NULL) { fts->cur = NULL; } else { fts->cur = (filename_trans_t*)fts->cur_item->key; } return STATUS_SUCCESS; } static size_t filename_trans_state_size(const qpol_iterator_t * iter) { filename_trans_state_t *fts = NULL; const policydb_t *db = NULL; size_t count = 0; unsigned int i = 0; if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return 0; } hashtab_ptr_t cur = NULL; for (i = 0; i < db->filename_trans->size; i++) { cur = db->filename_trans->htable[i]; while (cur != NULL) { count++; cur = cur->next; } } return count; } int qpol_policy_get_filename_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; filename_trans_state_t *fts = NULL; int error = 0; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; fts = calloc(1, sizeof(filename_trans_state_t)); if (!fts) { /* errno set by calloc */ ERR(policy, "%s", strerror(errno)); return STATUS_ERR; } fts->bucket = 0; fts->cur_item = db->filename_trans->htable[0]; fts->cur = NULL; fts->cur_item = db->filename_trans->htable[fts->bucket]; while (fts->cur_item == NULL) { fts->bucket++; if (fts->bucket >= db->filename_trans->size) { break; } fts->cur_item = db->filename_trans->htable[fts->bucket]; } if (fts->cur_item != NULL) { fts->cur = (filename_trans_t*)fts->cur_item->key; } if (qpol_iterator_create (policy, (void *)fts, filename_trans_state_get_cur, filename_trans_state_next, filename_trans_state_end, filename_trans_state_size, free, iter)) { error = errno; free(fts); errno = error; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_filename_trans_get_source_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** source) { policydb_t *db = NULL; filename_trans_t *ft = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ft = (filename_trans_t *) rule; *source = (qpol_type_t *) db->type_val_to_struct[ft->stype - 1]; return STATUS_SUCCESS; } int qpol_filename_trans_get_target_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** target) { policydb_t *db = NULL; filename_trans_t *ft = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ft = (filename_trans_t *) rule; *target = (qpol_type_t *) db->type_val_to_struct[ft->ttype - 1]; return STATUS_SUCCESS; } int qpol_filename_trans_get_object_class(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_class_t ** obj_class) { policydb_t *db = NULL; filename_trans_t *ft = NULL; if (obj_class) { *obj_class = NULL; } if (!policy || !rule || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ft = (filename_trans_t *) rule; *obj_class = (qpol_class_t *) db->class_val_to_struct[ft->tclass - 1]; return STATUS_SUCCESS; } int qpol_filename_trans_get_default_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** dflt) { policydb_t *db = NULL; filename_trans_t *ft = NULL; if (dflt) { *dflt = NULL; } if (!policy || !rule || !dflt) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ft = (filename_trans_t *) rule; /* Since the filename_trans rules were converted to being stored in a hashtab, otype was moved to the datum of the hashtab. * So we just look it up here. */ filename_trans_datum_t *datum = hashtab_search(db->filename_trans, (hashtab_key_t)ft); if (datum == NULL) { return STATUS_ERR; } *dflt = (qpol_type_t *) db->type_val_to_struct[datum->otype - 1]; return STATUS_SUCCESS; } int qpol_filename_trans_get_filename(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const char ** name) { filename_trans_t *ft = NULL; if (name) { *name = NULL; } if (!policy || !rule || !name) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } ft = (filename_trans_t *) rule; *name = ft->name; return STATUS_SUCCESS; } setools-4.1.1/libqpol/genfscon_query.c000066400000000000000000000152141314142262400200440ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over genfscon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" struct qpol_genfscon { const char *fs_name; const char *path; const context_struct_t *context; uint32_t sclass; }; int qpol_policy_get_genfscon_by_name(const qpol_policy_t * policy, const char *name, const char *path, qpol_genfscon_t ** genfscon) { genfs_t *tmp = NULL; ocontext_t *tmp2 = NULL; policydb_t *db = NULL; int error = 0; if (genfscon != NULL) *genfscon = NULL; if (policy == NULL || name == NULL || path == NULL || genfscon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->genfs; tmp; tmp = tmp->next) { if (!strcmp(name, tmp->fstype)) break; } if (tmp) { for (tmp2 = tmp->head; tmp2; tmp2 = tmp2->next) { if (!strcmp(path, tmp2->u.name)) break; } } if (tmp && tmp2) { *genfscon = calloc(1, sizeof(qpol_genfscon_t)); if (!(*genfscon)) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } /* shallow copy only the struct pointer (genfscon) should be free()'ed */ (*genfscon)->fs_name = tmp->fstype; (*genfscon)->path = tmp2->u.name; (*genfscon)->context = &(tmp2->context[0]); (*genfscon)->sclass = tmp2->v.sclass; } if (*genfscon == NULL) { ERR(policy, "could not find genfscon statement for %s %s", name, path); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } typedef struct genfs_state { genfs_t *head; genfs_t *cur; ocontext_t *cur_path; } genfs_state_t; static int genfs_state_end(const qpol_iterator_t * iter) { genfs_state_t *gs = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } gs = (genfs_state_t *) qpol_iterator_state(iter); if (gs->cur == NULL && gs->cur_path == NULL) return 1; return 0; } static void *genfs_state_get_cur(const qpol_iterator_t * iter) { genfs_state_t *gs = NULL; qpol_genfscon_t *genfscon = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL || genfs_state_end(iter)) { errno = EINVAL; return NULL; } gs = (genfs_state_t *) qpol_iterator_state(iter); genfscon = calloc(1, sizeof(qpol_genfscon_t)); if (!genfscon) { return NULL; } genfscon->fs_name = gs->cur->fstype; genfscon->path = gs->cur_path->u.name; genfscon->context = &(gs->cur_path->context[0]); genfscon->sclass = gs->cur_path->v.sclass; return genfscon; } static size_t genfs_state_size(const qpol_iterator_t * iter) { genfs_state_t *gs = NULL; size_t count = 0; genfs_t *genfs = NULL; ocontext_t *path = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } gs = (genfs_state_t *) qpol_iterator_state(iter); for (genfs = gs->head; genfs; genfs = genfs->next) for (path = genfs->head; path; path = path->next) count++; return count; } static int genfs_state_next(qpol_iterator_t * iter) { genfs_state_t *gs = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } gs = (genfs_state_t *) qpol_iterator_state(iter); if (gs->cur == NULL) { errno = ERANGE; return STATUS_ERR; } if (gs->cur_path->next != NULL) { gs->cur_path = gs->cur_path->next; } else { gs->cur = gs->cur->next; gs->cur_path = gs->cur ? gs->cur->head : NULL; } return STATUS_SUCCESS; } int qpol_policy_get_genfscon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; genfs_state_t *gs = NULL; int error = 0; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; gs = calloc(1, sizeof(genfs_state_t)); if (gs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } gs->head = gs->cur = db->genfs; if (gs->head) gs->cur_path = gs->head->head; if (qpol_iterator_create(policy, (void *)gs, genfs_state_get_cur, genfs_state_next, genfs_state_end, genfs_state_size, free, iter)) { free(gs); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_genfscon_get_name(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **name) { if (name != NULL) *name = NULL; if (policy == NULL || genfs == NULL || name == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *name = genfs->fs_name; return STATUS_SUCCESS; } int qpol_genfscon_get_path(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **path) { if (path != NULL) *path = NULL; if (policy == NULL || genfs == NULL || path == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *path = genfs->path; return STATUS_SUCCESS; } int qpol_genfscon_get_class(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, uint32_t * obj_class) { if (obj_class != NULL) *obj_class = 0; if (policy == NULL || genfs == NULL || obj_class == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *obj_class = genfs->sclass; return STATUS_SUCCESS; } int qpol_genfscon_get_context(const qpol_policy_t * policy, const qpol_genfscon_t * genfscon, const qpol_context_t ** context) { if (context != NULL) *context = NULL; if (policy == NULL || genfscon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *context = (qpol_context_t *) genfscon->context; return STATUS_SUCCESS; } setools-4.1.1/libqpol/include/000077500000000000000000000000001314142262400162715ustar00rootroot00000000000000setools-4.1.1/libqpol/include/qpol/000077500000000000000000000000001314142262400172445ustar00rootroot00000000000000setools-4.1.1/libqpol/include/qpol/avrule_query.h000066400000000000000000000224031314142262400221410ustar00rootroot00000000000000 /** * @file * Defines the public interface for searching and iterating over avrules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_AVRULE_QUERY_H #define QPOL_AVRULE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_avrule qpol_avrule_t; /* rule type defines (values copied from "sepol/policydb/policydb.h") */ #define QPOL_RULE_ALLOW 0x0001 #define QPOL_RULE_NEVERALLOW 0x0080 #define QPOL_RULE_AUDITALLOW 0x0002 /* dontaudit is actually stored as auditdeny so that value is used here */ #define QPOL_RULE_DONTAUDIT 0x0004 #define QPOL_RULE_AV (QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT) #define QPOL_RULE_XPERMS_ALLOW 0x0100 #define QPOL_RULE_XPERMS_AUDITALLOW 0x0200 #define QPOL_RULE_XPERMS_DONTAUDIT 0x0400 #define QPOL_RULE_XPERMS_NEVERALLOW 0x0800 #define QPOL_RULE_XPERMS (QPOL_RULE_XPERMS_ALLOW | QPOL_RULE_XPERMS_AUDITALLOW | QPOL_RULE_XPERMS_DONTAUDIT | QPOL_RULE_XPERMS_NEVERALLOW) /** * Get an iterator over all av rules in a policy of a rule type in * rule_type_mask. It is an error to call this function if rules are * not loaded. Likewise, it is an error if neverallows are requested * but they were not loaded. * @param policy Policy from which to get the av rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values. * It is an error to specify any of QPOL_RULE_TYPE_* in the mask. * @param iter Iterator over items of type qpol_avrule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_avrule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Get the source type from an av rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the source type. * @param source Pointer in which to store the source type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_avrule_get_source_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** source); /** * Get the target type from an av rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the target type. * @param target Pointer in which to store the target type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_avrule_get_target_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** target); /** * Get the object class from an av rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the object class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *obj_class will be NULL. */ extern int qpol_avrule_get_object_class(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_class_t ** obj_class); /** * Get an iterator over the permissions in an av rule. It is an error to call * this function on an extended avrule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the permissions. * @param perms Iterator over items of type char* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should call * free() on the strings returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *perms will be NULL. */ extern int qpol_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** perms); /** * Get an iterator over the extended permissions in an extended av rule. It is * an error to call this function an an avrule that is not an extended avrule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the permissions. * @param xperms Iterator over items of type int* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should call * free() on the ints returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *xperms will be NULL. */ extern int qpol_avrule_get_xperm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** xperms); /** * Determine if a rule is extnded. * @param policy Policy from which the rule comes. * @param rule The rule to check. * @param is_extended Integer in which to store the result: set to 1 if extended * and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_extended will be 0. */ extern int qpol_avrule_get_is_extended(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_extended); /** * Get the type of an extended permission * @param policy Policy from which the rule comes. * @param rule The extended rule from which to get the type. * @param type String in which to store the result. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *type will be NULL. */ int qpol_avrule_get_xperm_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, char ** type); /** * Get the rule type value for an av rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the rule type. * @param rule_type Integer in which to store the rule type value. * The value will be one of the QPOL_RULE_* values above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *rule_type will be 0. */ extern int qpol_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * rule_type); /** * Get the conditional from which an av rule comes. If the rule * is not a conditional rule *cond is set to NULL. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the conditional. * @param cond The conditional returned. (NULL if rule is not conditional) * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *cond will be NULL. If the rule is not conditional * *cond is set to NULL and the function is considered successful. */ extern int qpol_avrule_get_cond(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_cond_t ** cond); /** * Determine if a rule is enabled. Unconditional rules are always enabled. * @param policy Policy from which the rule comes. * @param rule The rule to check. * @param is_enabled Integer in which to store the result: set to 1 if enabled * and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_enabled will be 0. */ extern int qpol_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_enabled); /** * Get the list (true or false) in which a conditional rule is. It is * an error to call this function for an unconditional rule. * @param policy Policy from which the rule comes. * @param rule The rule to check. * @param which_list Integer in which to store the result: set to 1 if * rule is in the true list or 0 if in the false list. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *which_list will be 0. */ extern int qpol_avrule_get_which_list(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * which_list); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/include/qpol/bool_query.h000066400000000000000000000124621314142262400216020ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over booleans. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_BOOL_QUERY_H #define QPOL_BOOL_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_bool qpol_bool_t; /** * Get the datum for a conditional boolean by name. * @param policy The policy database from which to retrieve the boolean. * @param name The name of the boolean; searching is case sensitive. * @param datum Pointer to set to the boolean's datum entry in the policy. * This memory should not be freed by the user. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *datum will be NULL. */ extern int qpol_policy_get_bool_by_name(const qpol_policy_t * policy, const char *name, qpol_bool_t ** datum); /** * Get an iterator for conditional booleans in the policy. * @param policy The policy database from which to create the iterator. * @param iter Iterator of type qpol_bool_t* returned; * the user is responsible for calling qpol_iterator_destroy to * free memory used. It is also important to note that an iterator * is only valid as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_bool_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a boolean. Values range from 1 to * the number of conditional booleans declared in the policy. * @param policy The policy with which the boolean is associated. * @param datum Boolean datum from which to get the value. Must be non-NULL. * @param value Pointer to integer be set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *value will be 0. */ extern int qpol_bool_get_value(const qpol_policy_t * policy, const qpol_bool_t * datum, uint32_t * value); /** * Get the state of a boolean. * @param policy The policy with which the boolean is associated. * @param datum Boolean datum from which to get the state. Must be non-NULL. * @param state Pointer to the integer to be set to the boolean's state. * Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *state will set to 0 (false). */ extern int qpol_bool_get_state(const qpol_policy_t * policy, const qpol_bool_t * datum, int *state); /** * Set the state of a boolean and update the state of all conditionals * using the boolean. * @param policy The policy with which the boolean is associated. * The state of the policy is changed by this function. * @param datum Boolean datum for which to set the state. Must be non-NULL. * @param state Value to which to set the state of the boolean. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set. */ extern int qpol_bool_set_state(qpol_policy_t * policy, qpol_bool_t * datum, int state); /** * Set the state of a boolean but do not update the state of all conditionals * using the boolean. The caller is responsible for calling * qpol_policy_reevaluate_conds() at a later time to maintain a consistent * state of conditional expressions. * @param policy The policy with which the boolean is associated. * The state of the policy is changed by this function. * @param datum Boolean datum for which to set the state. Must be non-NULL. * @param state Value to which to set the state of the boolean. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set. */ extern int qpol_bool_set_state_no_eval(qpol_policy_t * policy, qpol_bool_t * datum, int state); /** * Get the name which identifies a boolean from its datum. * @param policy The policy with which the boolean is associated. * @param datum Boolean datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_bool_get_name(const qpol_policy_t * policy, const qpol_bool_t * datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_BOOL_QUERY_H */ setools-4.1.1/libqpol/include/qpol/bounds_query.h000066400000000000000000000155111314142262400221370ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the permissive types. * * @author Richard Haines richard_c_haines@btinternet.com * * Copyright (C) 2006-2009 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_BOUNDS_QUERY_H #define QPOL_BOUNDS_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include /************ TYPEBOUNDS *************/ typedef struct qpol_typebounds qpol_typebounds_t; /** * Get an iterator for the typebounds types in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_typebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a typebounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum typebounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_typebounds_get_parent_name(const qpol_policy_t *policy, const qpol_typebounds_t *datum, const char **name); /** * Get the name which identifies a typebounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum typebounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_typebounds_get_child_name(const qpol_policy_t *policy, const qpol_typebounds_t *datum, const char **name); /************ ROLEBOUNDS *************/ typedef struct qpol_rolebounds qpol_rolebounds_t; /** * Get an iterator for the rolebounds types in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_rolebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a rolebounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum rolebounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_rolebounds_get_parent_name(const qpol_policy_t *policy, const qpol_rolebounds_t *datum, const char **name); /** * Get the name which identifies a rolebounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum rolebounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_rolebounds_get_child_name(const qpol_policy_t *policy, const qpol_rolebounds_t *datum, const char **name); /************ USERBOUNDS *************/ typedef struct qpol_userbounds qpol_userbounds_t; /** * Get an iterator for the userbounds types in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_userbounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a userbounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum userbounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_userbounds_get_parent_name(const qpol_policy_t *policy, const qpol_userbounds_t *datum, const char **name); /** * Get the name which identifies a userbounds type from its datum. * @param policy The policy with which the type bounds type is associated. * @param datum userbounds datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_userbounds_get_child_name(const qpol_policy_t *policy, const qpol_userbounds_t *datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_BOUNDS_QUERY_H */ setools-4.1.1/libqpol/include/qpol/class_perm_query.h000066400000000000000000000224531314142262400230000ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * classes, commons, and permissions. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_CLASS_PERM_QUERY_H #define QPOL_CLASS_PERM_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_class qpol_class_t; typedef struct qpol_common qpol_common_t; /* perms */ /** * Get an iterator over the set of classes which contain a permission * with the name perm. This function does not search for the permission * in the class's inherited common. * @param policy The policy from which to query the classes. * @param perm The name of the permission to be matched. Must be non-NULL. * @param classes The iterator of type qpol_class_t returned; * the user is responsible for calling qpol_iterator_destroy * to free memory used. It is also important to note * that an iterator is only valid as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *classes will be NULL; */ extern int qpol_perm_get_class_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** classes); /** * Get an iterator over the set of commons which contain a permission * with the name perm. * @param policy The policy from which to query the commons. * @param perm The name of the permission to be matched. Must be non-NULL. * @param commons The iterator of type qpol_common_t returned; * the user is responsible for calling qpol_iterator_destroy * to free memory used. It is also important to note * that an iterator is only valid as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *commons will be NULL; */ extern int qpol_perm_get_common_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** commons); /* classes */ /** * Get an object class by name. * @param policy The policy from which to get the class. * @param name The name of the class; searching is case sensitive. * @param obj_class Pointer in which to store the class. * Caller should not free this pointer. * @return Returns 0 for success and < 0 for failure; if the call fails, * errno will be set and *obj_class will be NULL; */ extern int qpol_policy_get_class_by_name(const qpol_policy_t * policy, const char *name, const qpol_class_t ** obj_class); /** * Get an iterator for object classes in the policy. * @param policy The policy database from which to create the iterator. * @param iter Iterator of type qpol_class_t* returned; the user * is responsible for calling qpol_iterator_destroy to free memory used. * It is also important to note that an iterator is only valid as long * as the policy is unchanged. * @return Returns 0 for success and < 0 for failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_class_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a class. Values range from 1 to * the number of object classes declared in the policy. * @param policy The policy with which the class is associated. * @param obj_class Class from which to get the value. Must be non-NULL. * @param value Pointer to the integer to be set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *value will be 0. */ extern int qpol_class_get_value(const qpol_policy_t * policy, const qpol_class_t * obj_class, uint32_t * value); /** * Get the common used by a class. * @param policy The policy with which the class is associated. * @param obj_class Class from which to get the value. Must be non-NULL. * @param common Pointer to the common associated with this * class; the caller should not free this pointer. Not all classes have an * associated common so it is possible for *common to be NULL on success. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *common will be NULL. */ extern int qpol_class_get_common(const qpol_policy_t * policy, const qpol_class_t * obj_class, const qpol_common_t ** common); /** * Get an iterator for the set of (unique) permissions for a class. * @param policy The policy with which the class is associated. * @param obj_class The class from which to get the permissions. * @param perms Iterator of type char* returned for the list of * permissions for this class. The list only contains permissions unique * to the class not those included from a common. The iterator is only * valid as long as the policy is unchanged; the caller is responsible * for calling qpol_iterator_destroy to free memory used. * @return Returns 0 for success and < 0 for failure; if the call fails, * errno will be set and *perms will be NULL. */ extern int qpol_class_get_perm_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** perms); /** * Get the name which identifies a class. * @param policy The policy with which the class is associated. * @param obj_class Class for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. Caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_class_get_name(const qpol_policy_t * policy, const qpol_class_t * obj_class, const char **name); /* commons */ /** * Get a common by name. * @param policy from which to get the common. * @param name The name of the common; searching is case sensitive. * @param common Pointer in which to store the common. * Caller should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *common will be NULL. */ extern int qpol_policy_get_common_by_name(const qpol_policy_t * policy, const char *name, const qpol_common_t ** common); /** * Get an iterator for commons in the policy * @param policy The policy from which to create the iterator. * @param iter Iterator of type qpol_common_t* returned; * the user is responsible for calling qpol_iterator_destroy to * free memory used. It is also important to note that an iterator is * only valid as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_common_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a common. Values range from 1 to * the number of commons declared in the policy. * @param policy The policy associated with the common. * @param common The common from which to get the value. * @param value Pointer to the integer to be set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *value will be 0. */ extern int qpol_common_get_value(const qpol_policy_t * policy, const qpol_common_t * common, uint32_t * value); /** * Get an iterator for the permissions included in a common. * @param policy The policy associated with the common. * @param common The common from which to get permissions. * @param perms Iterator of type char* returned for the list of * permissions for this common. The iterator is only valid as long * as the policy is unchanged; the caller is responsible for calling * qpol_iterator_destroy to free memory used. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *perms will be NULL. */ extern int qpol_common_get_perm_iter(const qpol_policy_t * policy, const qpol_common_t * common, qpol_iterator_t ** perms); /** * Get the name which identifies a common. * @param policy associated with the common. * @param common The common from which to get the name. * @param name Pointer in which to store the name. Must be non-NULL; * the caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_common_get_name(const qpol_policy_t * policy, const qpol_common_t * common, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_CLASS_PERM_QUERY_H */ setools-4.1.1/libqpol/include/qpol/cond_query.h000066400000000000000000000210551314142262400215700ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * conditionals * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_COND_QUERY_H #define QPOL_COND_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include typedef struct qpol_cond qpol_cond_t; typedef struct qpol_cond_expr_node qpol_cond_expr_node_t; /** * Get an iterator over all conditionals in a policy. * It is an error to call this function if rules are not loaded. * @param policy Policy from which to get the conditionals. * @param iter Iterator over items of type qpol_cond_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used in this iterator. * It is important to node that this iterator is only valid as long as * the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_cond_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get an iterator over the nodes in a conditional expression. * Each node represents a single token of the expression in RPN. * @param policy The policy associated with the conditional. * @param cond The conditional from which to get the expression. * @param iter Iterator over items of type qpol_cond_expr_node_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used in this iterator. * It is important to node that this iterator is only valid as long as * the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_cond_get_expr_node_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, qpol_iterator_t ** iter); /* flags for conditional rules */ #define QPOL_COND_RULE_LIST 0x00000001 #define QPOL_COND_RULE_ENABLED 0x00000002 /** * Get an iterator over all av rules in a conditional's true list * of a rule type in rule_type_mask. * @param policy The policy associated with the conditional. * @param cond The conditional from which to get the rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values * (see avrule_query.h) to include. * @param iter Iterator over items of type qpol_avrule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_cond_get_av_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Get an iterator over all type rules in a conditional's true list * of a rule type in rule_type_mask. * @param policy The policy associated with the conditional. * @param cond The conditional from which to get the rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values * (see terule_query.h) to include. * @param iter Iterator over items of type qpol_terule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_cond_get_te_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Get an iterator over all av rules in a conditional's false list * of a rule type in rule_type_mask. * @param policy The policy associated with the conditional. * @param cond The conditional from which to get the rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values * (see avrule_query.h) to include. * @param iter Iterator over items of type qpol_avrule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_cond_get_av_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Get an iterator over all type rules in a conditional's false list * of a rule type in rule_type_mask. * @param policy The policy associated with the conditional. * @param cond The conditional from which to get the rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values * (see terule_query.h) to include. * @param iter Iterator over items of type qpol_avrule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_cond_get_te_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Evaluate the expression of a conditional using current boolean values * in the policy. * @param policy The policy associated with the conditional. * @param cond The conditional to evaluate. * @param is_true Integer in which to store the result of evaluating the * the expression, will be 1 if true and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_true will be 0. */ extern int qpol_cond_eval(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t * is_true); /* values identical to conditional.h in sepol */ #define QPOL_COND_EXPR_BOOL 1 /* plain bool */ #define QPOL_COND_EXPR_NOT 2 /* !bool */ #define QPOL_COND_EXPR_OR 3 /* bool || bool */ #define QPOL_COND_EXPR_AND 4 /* bool && bool */ #define QPOL_COND_EXPR_XOR 5 /* bool ^ bool */ #define QPOL_COND_EXPR_EQ 6 /* bool == bool */ #define QPOL_COND_EXPR_NEQ 7 /* bool != bool */ /** * Get the type of an expression node. * @param policy The policy associated with the conditional expression. * @param node The node from which to get the expression type. * @param expr_type Integer in which to store the expression type; * the value will be one of QPOL_COND_EXPR_* above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *expr_type will be 0. */ extern int qpol_cond_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, uint32_t * expr_type); /** * Get the boolean used in an expression node. This is only valid * when the node's expression type is QPOL_COND_EXPR_BOOL. * @param policy The policy associated with the conditional experssion. * @param node The node from which to get the boolean. It is an error * to call this function if the node is not of type QPOL_COND_EXPR_BOOL. * @param cond_bool Pointer in which to store the boolean. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *cond_bool will be NULL. */ extern int qpol_cond_expr_node_get_bool(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, qpol_bool_t ** cond_bool); #ifdef __cplusplus } #endif #endif /* QPOL_COND_QUERY_H */ setools-4.1.1/libqpol/include/qpol/constraint_query.h000066400000000000000000000272151314142262400230350ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * constraints * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_CONSTRAINT_QUERY_H #define QPOL_CONSTRAINT_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include typedef struct qpol_constraint qpol_constraint_t; typedef struct qpol_validatetrans qpol_validatetrans_t; typedef struct qpol_constraint_expr_node qpol_constraint_expr_node_t; /** * Get an iterator for the constraints in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_constraint_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_constraint_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the object class from a constraint. * @param policy The policy associated with the constraint. * @param constr The constraint from which to get the class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *obj_class will be NULL. */ extern int qpol_constraint_get_class(const qpol_policy_t * policy, const qpol_constraint_t * constr, const qpol_class_t ** obj_class); /** * Get an iterator over the permissions in a constraint. * @param policy The policy from which the constraint comes. * @param constr The constraint from which to get the permissions. * @param iter Iterator over items of type char*. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should call * free() on the strings returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_constraint_get_perm_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter); /** * Get an iterator over the nodes in a constraint expression. * @param policy The policy from which the constraint comes. * @param constr The constraint from which to get the expression. * @param iter Iterator over items of type qpol_constraint_expr_node_t. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should not * free the items returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_constraint_get_expr_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter); /** * Get an iterator for the validatetrans statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_validatetrans_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_validatetrans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the object class from a validatetrans statement. * @param policy The policy associated with the validatetrans statement. * @param vtrans The validatetrans statement from which to get the class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *obj_class will be NULL. */ extern int qpol_validatetrans_get_class(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, const qpol_class_t ** obj_class); /** * Get an iterator over the nodes in a validatetrans expression. * @param policy The policy from which the validatetrans statement comes. * @param vtrans The validatetrans statement from which to get the expression. * @param iter Iterator over items of type qpol_constraint_expr_node_t. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should not * free the items returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_validatetrans_get_expr_iter(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, qpol_iterator_t ** iter); /* expr_type values */ #define QPOL_CEXPR_TYPE_NOT 1 #define QPOL_CEXPR_TYPE_AND 2 #define QPOL_CEXPR_TYPE_OR 3 #define QPOL_CEXPR_TYPE_ATTR 4 #define QPOL_CEXPR_TYPE_NAMES 5 /** * Get the code for the expression type of by an expression node. * @param policy The policy from which the expression comes. * @param expr The expression node from which to get the expression type. * @param expr_type Integer in which to store the expression type; the value * will be one of QPOL_CEXPR_TYPE_* above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *op will be 0. */ extern int qpol_constraint_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * expr_type); /* attr values */ #define QPOL_CEXPR_SYM_USER 1 #define QPOL_CEXPR_SYM_ROLE 2 #define QPOL_CEXPR_SYM_TYPE 4 #define QPOL_CEXPR_SYM_TARGET 8 #define QPOL_CEXPR_SYM_XTARGET 16 #define QPOL_CEXPR_SYM_L1L2 32 #define QPOL_CEXPR_SYM_L1H2 64 #define QPOL_CEXPR_SYM_H1L2 128 #define QPOL_CEXPR_SYM_H1H2 256 #define QPOL_CEXPR_SYM_L1H1 512 #define QPOL_CEXPR_SYM_L2H2 1024 /** * Get the code for the symbol type used by an expression node. * @param policy The policy from which the expression comes. * @param expr The expression node from which to get the symbol type. * Must be of expression type QPOL_CEXPR_TYPE_ATTR or QPOL_CEXPR_TYPE_NAMES. * @param sym_type Integer in which to store the symbol type; the value * will be a bitwise or'ed set of QPOL_CEXPR_SYM_* above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *sym_type will be 0. */ extern int qpol_constraint_expr_node_get_sym_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * sym_type); /* op values */ #define QPOL_CEXPR_OP_EQ 1 #define QPOL_CEXPR_OP_NEQ 2 #define QPOL_CEXPR_OP_DOM 3 #define QPOL_CEXPR_OP_DOMBY 4 #define QPOL_CEXPR_OP_INCOMP 5 /** * Get the operator used by an expression node. * @param policy The policy from which the expression comes. * @param expr The expression node from which to get the operator. * Must be of expression type QPOL_CEXPR_TYPE_ATTR or QPOL_CEXPR_TYPE_NAMES. * @param op Integer in which to store the operator; the value * will be one of QPOL_CEXPR_OP_* above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *op will be 0. */ extern int qpol_constraint_expr_node_get_op(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * op); /** * Get an iterator of the names in an expression node. * @param policy The policy from which the expression comes. * @param expr The expression node from which to create the iterator. * Must be of expression type QPOL_CEXPR_TYPE_NAMES. * @param iter Iterator over items of type char* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller should call * free() on the strings returned by qpol_iterator_get_item(). * It is important to note that this iterator is only valid as long * as the policy is unmodified. * In the case where the symbol names are types, the name of a subtracted * type will be prepended with a '-' character. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_constraint_expr_node_get_names_iter(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, qpol_iterator_t ** iter); /** * Get an iterator for the constraints on a class. * @param policy The policy associated with the class. * @param obj_class The class from which to create the iterator. * @param constr Iterator over items of type qpol_constraint_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *constr will be NULL. */ extern int qpol_class_get_constraint_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** constr); /** * Get an iterator for the validatetrans statements for a class. * @param policy The policy associated with the class. * @param obj_class The class from which to create the iterator. * @param vtrans Iterator over items of type qpol_validatetrans_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *vtrans will be NULL. */ extern int qpol_class_get_validatetrans_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** vtrans); #ifdef __cplusplus } #endif #endif /* QPOL_CONSTRAINT_QUERY_H */ setools-4.1.1/libqpol/include/qpol/context_query.h000066400000000000000000000066401314142262400223340ustar00rootroot00000000000000/** * @file * Defines the public interface accessing contexts. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_CONTEXT_QUERY_H #define QPOL_CONTEXT_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include typedef struct qpol_context qpol_context_t; /** * Get the datum for the user field of a context. * @param policy The policy associated with the context. * @param context The context from which to get the user. * @param user Pointer in which to store the user datum. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *user will be NULL. */ extern int qpol_context_get_user(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_user_t ** user); /** * Get the datum for the role field of a context. * @param policy The policy associated with the context. * @param context The context from which to get the role. * @param role Pointer in which to store the role datum. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *role will be NULL. */ extern int qpol_context_get_role(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_role_t ** role); /** * Get the datum for the type field of a context. * @param policy The policy associated with the context. * @param context The context from which to get the type. * @param type Pointer in which to store the type datum. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *type will be NULL. */ extern int qpol_context_get_type(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_type_t ** type); /** * Get the datum for the MLS range field of a context. * @param policy The policy associated with the context. * @param context The context from which to get the MLS range. * @param range Pointer in which to store the MLS range. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *range will be NULL. */ extern int qpol_context_get_range(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_mls_range_t ** range); #ifdef __cplusplus } #endif #endif /* QPOL_CONTEXT_QUERY_H */ setools-4.1.1/libqpol/include/qpol/default_object_query.h000066400000000000000000000115441314142262400236210ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over default objects. * * @author Richard Haines richard_c_haines@btinternet.com * * Copyright (C) 2006-2009 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_DEFAULT_OBJECT_QUERY_H #define QPOL_DEFAULT_OBJECT_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_default_object qpol_default_object_t; /** * Get an iterator for the default_object types in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_default_object_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a default_object class from its datum. * @param policy The policy with which class is associated. * @param datum default_object datum for which to get the name. Must be non-NULL. * @param cls Pointer to the class object. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_default_object_get_class(const qpol_policy_t *policy, const qpol_default_object_t *datum, const qpol_class_t **cls); /** * Get the value of a default user source/dest from its datum. * @param policy The policy with which the default object is associated. * @param datum default_object datum for which to get the value. Must be non-NULL. * @param value Pointer to the value in which to store the default. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *default will be 0. */ extern int qpol_default_object_get_user_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); /** * Get the value of a default role source/dest from its datum. * @param policy The policy with which the default object type is associated. * @param datum default_object datum for which to get the value. Must be non-NULL. * @param value Pointer to the value in which to store the default. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *default will be 0. */ extern int qpol_default_object_get_role_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); /** * Get the value of a default type source/dest from its datum. * @param policy The policy with which the default object type is associated. * @param datum default_object datum for which to get the value. Must be non-NULL. * @param value Pointer to the value in which to store the default. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *default will be 0. */ extern int qpol_default_object_get_type_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); /** * Get the value of a default range source/dest from its datum. * @param policy The policy with which the default object type is associated. * @param datum default_object datum for which to get the value. Must be non-NULL. * @param value Pointer to the value in which to store the default. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *default will be 0. */ extern int qpol_default_object_get_range_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/include/qpol/fs_use_query.h000066400000000000000000000107411314142262400221310ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over fs_use statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_FS_USE_QUERY_H #define QPOL_FS_USE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include typedef struct qpol_fs_use qpol_fs_use_t; /** * Get a fs_use statement by file system name. * @param policy The policy from which to get the fs_use statement. * @param name The name of the file system. * @param ocon Pointer in which to store the fs_use statement. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_fs_use_by_name(const qpol_policy_t * policy, const char *name, const qpol_fs_use_t ** ocon); /** * Get an iterator for the fs_use statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_fs_use_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_fs_use_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the file system name from a fs_use statement. * @param policy The policy associated with the fs_use statement. * @param ocon The fs_use statement from which to get the name. * @param name Pointer to the string in which to store the name. * The caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_fs_use_get_name(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const char **name); /* The defines QPOL_FS_USE_XATTR through QPOL_FS_USE_NONE are * copied from sepol/policydb/services.h. * QPOL_FS_USE_PSID is an extension to support v12 policies. */ #define QPOL_FS_USE_XATTR 1U #define QPOL_FS_USE_TRANS 2U #define QPOL_FS_USE_TASK 3U #define QPOL_FS_USE_GENFS 4U #define QPOL_FS_USE_NONE 5U #define QPOL_FS_USE_PSID 6U /** * Get the labeling behavior from a fs_use statement. * @param policy The policy associated with the fs_use statement. * @param ocon The fs_use statement from which to get the behavior. * @param behavior Pointer to be set to the value of the labeling behavior. * The value will be one of the QPOL_FS_USE_* values defined above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *behavior will be 0. */ extern int qpol_fs_use_get_behavior(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, uint32_t * behavior); /** * Get the context from a fs_use statement. * @param policy The policy associated with the fs_use statement. * @param ocon The fs_use statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. It is considered an * error to call this function if behavior is QPOL_FS_USE_PSID. */ extern int qpol_fs_use_get_context(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_FS_USE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/ftrule_query.h000066400000000000000000000111121314142262400221370ustar00rootroot00000000000000/** * @file * Defines public interface for iterating over FTRULE rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_FTRULE_QUERY #define QPOL_FTRULE_QUERY #ifdef __cplusplus extern "C" { #endif #include #include typedef struct qpol_filename_trans qpol_filename_trans_t; /** * Get an iterator over all filename transition rules in the policy. * @param policy Policy from which to create the iterator. * @param iter Iterator over items of type qpol_filename_trans_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_filename_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the source type from a filename transition rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the source type. * @param source Pointer in which to store the source type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_filename_trans_get_source_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** source); /** * Get the target type from a filename transition rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the target type. * @param target Pointer in which to store the target type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_filename_trans_get_target_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** target); /** * Get the default type from a filename transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the default type. * @param dflt Pointer in which to store the default type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *dflt will be NULL. */ extern int qpol_filename_trans_get_default_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** dflt); /** * Get the object class from a filename transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the object class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *obj_class will be NULL. */ extern int qpol_filename_trans_get_object_class(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_class_t ** obj_class); /** * Get the filename from a filename transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the transition filename. * @param name Pointer in which to store the filename. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_filename_trans_get_filename(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const char ** name); #ifdef __cplusplus } #endif #endif /* QPOL_FTRULE_QUERY */ setools-4.1.1/libqpol/include/qpol/genfscon_query.h000066400000000000000000000121541314142262400224470ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over genfscon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 20062007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_OCON_QUERY_H #define QPOL_OCON_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_genfscon qpol_genfscon_t; /** * Get a genfscon statement by file system name and path. * @param policy The policy from which to get the genfscon statement. * @param name The name of the file system. * @param path The path relative to the filesystem mount point. * @param genfscon Pointer in which to store the genfscon statement. * The caller should call free() on this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *genfscon will be NULL. */ extern int qpol_policy_get_genfscon_by_name(const qpol_policy_t * policy, const char *name, const char *path, qpol_genfscon_t ** genfscon); /** * Get an iterator for the genfscon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_genfscon_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_genfscon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the file system name from a gefscon statement. * @param policy The policy associated with the genfscon statement. * @param genfs The genfscon statement from which to get the name. * @param name Pointer to th string in which to store the name. * The caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_genfscon_get_name(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **name); /** * Get the relative path from a gefscon statement. * @param policy The policy associated with the genfscon statement. * @param genfs The genfscon statement from which to get the path. * @param path Pointer to the string in which to store the path. * The caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *path will be NULL. */ extern int qpol_genfscon_get_path(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **path); /* values from flask do not change */ #define QPOL_CLASS_ALL 0U #define QPOL_CLASS_BLK_FILE 11U #define QPOL_CLASS_CHR_FILE 10U #define QPOL_CLASS_DIR 7U #define QPOL_CLASS_FIFO_FILE 13U #define QPOL_CLASS_FILE 6U #define QPOL_CLASS_LNK_FILE 9U #define QPOL_CLASS_SOCK_FILE 12U /** * Get the object class from a genfscon statement. * @param policy The policy associated with the genfscon statement. * @param genfs The genfscon statement from which to get the path. * @param obj_class Pointer in which to store the integer code for the * object class. See QPOL_CLASS_* defines above for values. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *class will be 0. */ extern int qpol_genfscon_get_class(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, uint32_t * obj_class); /** * Get the context from a path component of a genfscon statement. * @param policy The policy associated with the genfscon statement. * @param genfscon The genfscon statement from which to get * the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_genfscon_get_context(const qpol_policy_t * policy, const qpol_genfscon_t * genfscon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_OCON_QUERY_H */ setools-4.1.1/libqpol/include/qpol/isid_query.h000066400000000000000000000066301314142262400215770ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over initial SIDs. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_ISID_QUERY_H #define QPOL_ISID_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_isid qpol_isid_t; /** * Get an initial SID statement by name. * @param policy The policy from which to get the initial SID statement. * @param name The name of the initial SID. * @param ocon Pointer in which to store the initial SID. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_isid_by_name(const qpol_policy_t * policy, const char *name, const qpol_isid_t ** ocon); /** * Get an iterator for the initial SID statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_isid_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the name from an initial SID statement. * @param policy The policy associated with the initial SID. * @param ocon The initial SID from which to get the name. * @param name Pointer to the string in which to store the name. * The caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_isid_get_name(const qpol_policy_t * policy, const qpol_isid_t * ocon, const char **name); /** * Get the context from an initial SID statement. * @param policy The policy associated with the inital SID. * @param ocon The initial SID from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_isid_get_context(const qpol_policy_t * policy, const qpol_isid_t * ocon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_ISID_QUERY_H */ setools-4.1.1/libqpol/include/qpol/iterator.h000066400000000000000000000065771314142262400212650ustar00rootroot00000000000000/** * @file * Defines the public API for qpol_iterator; this structure * is used when requesting lists of components from the policy * database. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_ITERATOR_H #define QPOL_ITERATOR_H #ifdef __cplusplus extern "C" { #endif #include struct qpol_iterator; typedef struct qpol_iterator qpol_iterator_t; /** * Free memory used by the iterator. * @param iter Pointer to the iterator to be freed; frees all * memory used by the iterator and the iterator itself. On returning * *iter will be NULL. */ extern void qpol_iterator_destroy(qpol_iterator_t ** iter); /** * Get the item at the current position of the iterator. * @param iter The iterator from which to get the item. * @param item Pointer in which to store the current item; the caller is * responsible for safely casting this pointer. Unless specifically * noted by the function creating the iterator, the item set * by this function should not be freed. If the iterator is at * the end (i.e. all items have been traversed) *item will be NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *item will be NULL. */ extern int qpol_iterator_get_item(const qpol_iterator_t * iter, void **item); /** * Advance the iterator to the next item. * @param iter The iterator to advance; internal state data will change. * @return Returns 0 on success and < 0 on failure; advancing an * iterator that is at the end fails (and returns < 0). If the call fails, * errno will be set. */ extern int qpol_iterator_next(qpol_iterator_t * iter); /** * Determine if an iterator is at the end. * @param iter The iterator to check. * @return Returns non-zero if the current position of the iterator * is at the end of the list (i.e. past the last valid item) and * zero in any other case. If there is an error determining if * the iterator is at the end then non-zero will be returned. */ extern int qpol_iterator_end(const qpol_iterator_t * iter); /** * Get the total number of items in the list traversed by the iterator. * @param iter The iterator from which to get the number of items. * @param size Pointer in which to store the number of items. * Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *size will be 0. */ extern int qpol_iterator_get_size(const qpol_iterator_t * iter, size_t * size); #ifdef __cplusplus } #endif #endif /* QPOL_ITERATOR */ setools-4.1.1/libqpol/include/qpol/linux_types.h000066400000000000000000000004271314142262400220030ustar00rootroot00000000000000#ifndef linux_types_h #define linux_types_h #ifdef __linux__ # include "linux/types.h" #else # include typedef int32_t __s32; typedef uint32_t __u32; typedef uint8_t __u8; typedef uint16_t __u16; #define s6_addr32 __u6_addr32 #define IPPROTO_DCCP 33 #endif #endif setools-4.1.1/libqpol/include/qpol/mls_query.h000066400000000000000000000302441314142262400214400ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * policy MLS components. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_MLS_QUERY_H #define QPOL_MLS_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include typedef struct qpol_level qpol_level_t; typedef struct qpol_cat qpol_cat_t; typedef struct qpol_mls_range qpol_mls_range_t; typedef struct qpol_mls_level qpol_mls_level_t; typedef struct qpol_semantic_level qpol_semantic_level_t; #include #include /* level */ /** * Get datum for a security level by (sensitivity) name. * @param policy The policy from which to get the level datum. * @param name The sensitivity name; searching is case sensitive. * @param datum Pointer in which to store the level datum. Must be non-NULL. * The caller should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *datum will be NULL. */ extern int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum); /** * Get an iterator for the levels in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator of type qpol_level_t* returned; * The caller is responsible for calling qpol_iterator_destroy * to free memory used; it is important to note that the iterator * is valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Determine if a level is an alias for another level. * @param policy The policy associated with the level datum. * @param datum The level to check. * @param isalias Pointer in which to store the alias state of * the level. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *isalias will be 0 (false). */ extern int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias); /** * Get the integer value associated with the sensitivity of a level. * Values range from 1 to the number of declared levels in the policy. * @param policy The policy associated with the level. * @param datum The level datum from which to get the value. * @param value Pointer to the integer to set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *value will be 0. */ extern int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value); /** * Get an iterator for the categories associated with a level. * @param policy The policy associated with the level. * @param datum The level from which to get the categories. * @param cats Iterator of type qpol_cat_t* returned; * the categories are in policy order. The caller is responsible * for calling qpol_iterator_destroy to free memory used; * it is important to note that the iterator is valid only as long * as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *cats will be NULL. */ extern int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats); /** * Get the name which identifies a level from its datum. * @param policy The policy associated with the level. * @param datum The level from which to get the name. * @param name Pointer in which to store the name. Must be non-NULL; * the caller should not free this string. If the sensitivity is an * alias, the primary name will be returned. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name); /** * Get an iterator for the list of aliases for a level. * @param policy The policy associated with the level. * @param datum The level for which to get aliases. * @param aliases Iterator of type char* returned; the caller is * responsible for calling qpol_iterator_destroy to free * memory used; it is important to note that the iterator is valid * only as long as the policy is unchanged. If a level has no aliases, * the iterator will be at end and have size 0. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *aliases will be NULL. */ extern int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases); /* cat */ /** * Get the datum for a category by name. * @param policy The policy from which to get the category. * @param name The name of the category; searching is case sensitive. * @param datum Pointer in which to store the datum; the caller should * not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *datum will be NULL. */ extern int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum); /** * Get an iterator for the categories declared in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator of type qpol_cat_t* returned; * the categories are in policy order. The caller is responsible * for calling qpol_iterator_destroy to free the memory used; * it is important to note that the iterator is only valid as * long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a category. Values range * from 1 to the number of categories declared in the policy. * @param policy The policy associated with the category. * @param datum The category for which to get the value. * @param value Pointer to the integer to set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *value will be 0. */ extern int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value); /** * Determine if a category is an alias for another category. * @param policy The policy associated with the category. * @param datum The category to check. * @param isalias Pointer in which to store the alias state of the * category; must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *isalias will be 0 (false). */ extern int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias); /** * Get the name which identifies a category from its datum. * @param policy The policy associated with the category. * @param datum The category from which to get the name. * @param name Pointer in which to store the name. Must be non-NULL; * the caller should not free the string. If the category is an alias * the primary name will be returned. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name); /** * Get an iterator for the list of aliases for a category. * @param policy The policy associated with the category. * @param datum The category for which to get aliases. * @param aliases Iterator of type char* returned; the caller is * responsible for calling qpol_iterator_destroy to free * memory used; it is important to note that the iterator is valid * only as long as the policy is unchanged. If a category has no aliases, * the iterator will be at end and have size 0. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *aliases will be NULL. */ extern int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases); /* mls range */ /** * Get the low level from a MLS range. * @param policy The policy associated with the MLS components of range. * @param range The range from which to get the low level. * @param level Pointer in which to store the level; the caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *level will be NULL. */ extern int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level); /** * Get the high level from a MLS range. * @param policy The policy associated with the MLS components of range. * @param range The range from which to get the high level. * @param level Pointer in which to store the level; the caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *level will be NULL. */ extern int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level); /* mls_level */ /** * Get the name of the sensitivity from a MLS level. * @param policy The policy associated with the MLS components of level. * @param level The level from which to get the sensitivity name. * @param name Pointer in which to store the name; the caller * should not free this string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name); /** * Get an iterator for the categories in a MLS level. The list will be * in policy order. * @param policy The policy associated with the MLS components of level. * @param level The level from which to get the categories. * @param cats Iterator of type qpol_cat_t* returned; the list is in * policy order. The caller is responsible for calling * qpol_iterator_destroy to free memory used; it is important to note * that an iterator is only valid as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *cats will be NULL. */ extern int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats); /* semantic levels */ extern int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_semantic_level_t ** datum); extern int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high); extern int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, const qpol_semantic_level_t * src, qpol_mls_level_t **dest); extern void qpol_semantic_level_destroy(qpol_semantic_level_t * level); /* semantic ranges */ extern int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t * low, const qpol_mls_level_t *high, qpol_mls_range_t **dest); #ifdef __cplusplus } #endif #endif /* QPOL_MLS_QUERY_H */ setools-4.1.1/libqpol/include/qpol/mlsrule_query.h000066400000000000000000000077631314142262400223420ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * range transition rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_MLSRULE_QUERY_H #define QPOL_MLSRULE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include typedef struct qpol_range_trans qpol_range_trans_t; /** * Get an iterator over all range transition rules in a policy. * @param policy Policy from which to get the range transitions. * @param iter Iterator over items of type qpol_range_trans_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_range_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the source type from a range transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the source type. * @param source Pointer in which to store the source type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_range_trans_get_source_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** source); /** * Get the target type from a range transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the target type. * @param target Pointer in which to store the target type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_range_trans_get_target_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** target); /** * Get the target class from a range transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the target class. * @param target Pointer in which to store the target class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_range_trans_get_target_class(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_class_t ** target); /** * Get the range from a range transition rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the range. * @param range Pointer in which to store the range. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *range will be NULL. */ extern int qpol_range_trans_get_range(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_mls_range_t ** range); #ifdef __cplusplus } #endif #endif /* QPOL_MLSRULE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/module.h000066400000000000000000000111561314142262400207060ustar00rootroot00000000000000/** * @file * Defines the public interface the policy modules. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_MODULE_H #define QPOL_MODULE_H #ifdef __cplusplus extern "C" { #endif #include typedef struct qpol_module qpol_module_t; #define QPOL_MODULE_UNKNOWN 0 #define QPOL_MODULE_BASE 1 #define QPOL_MODULE_OTHER 2 /** * Create a qpol module from a policy package file. Newly created * modules are enabled by default. * @param path The file from which to read the module. This string * will be duplicated. * @param module Pointer in which to store the newly allocated * module. The caller is responsible for calling qpol_module_destroy() * to free memory used by this module. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *module will be NULL. */ extern int qpol_module_create_from_file(const char *path, qpol_module_t ** module); /** * Free all memory used by a qpol module and set it to NULL. Does * nothing if the pointer is already NULL. * @param module Reference pointer to the module to destroy. */ extern void qpol_module_destroy(qpol_module_t ** module); /** * Get the path of the policy package file used to create this module. * @param module The module from which to get the path. * @param path Pointer to the string in which to store the path. The * caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *path will be NULL. */ extern int qpol_module_get_path(const qpol_module_t * module, const char **path); /** * Get the name of a module. * @param module The module from which to get the name. * @param name Pointer to the string in which to store the name. The * caller should not free this string. If the module is a base * module the name will be NULL. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_module_get_name(const qpol_module_t * module, const char **name); /** * Get the version of a module. * @param module The module from which to get the version. * @param version Pointer to string in which to store the version. The * caller should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *version will be NULL. */ extern int qpol_module_get_version(const qpol_module_t * module, const char **version); /** * Get the type of module (base or other). * @param module The module from which to get the type. * @param type Pointer to integer in which to store the type. Value * will be one of QPOL_MODULE_BASE or QPOL_MODULE_OTHER. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *type will be QPOL_MODULE_UNKNOWN. */ extern int qpol_module_get_type(const qpol_module_t * module, int *type); /** * Determine if a module is enabled. * @param module The module from which to get the enabled state. * @param enabled Pointer to integer in which to store the state. * Value will be 0 if module is disabled and non-zero if enabled. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *enabled will be 0. */ extern int qpol_module_get_enabled(const qpol_module_t * module, int *enabled); /** * Enable or disable a module. Note that the caller must still * invoke qpol_policy_rebuild() to update the policy. * @param module The module to enable or disable. * @param enabled Non-zero to enable the module, zero to disable. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and the module will remain unchanged. */ extern int qpol_module_set_enabled(qpol_module_t * module, int enabled); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/include/qpol/netifcon_query.h000066400000000000000000000101171314142262400224470ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over netifcon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_NETIFCON_QUERY_H #define QPOL_NETIFCON_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_netifcon qpol_netifcon_t; /** * Get a netifcon statement by interface name. * @param policy The policy from which to get the netifcon statement. * @param name The name of the interface. * @param ocon Pointer in which to store the statement returned. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_netifcon_by_name(const qpol_policy_t * policy, const char *name, const qpol_netifcon_t ** ocon); /** * Get an iterator for the netifcon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_netifcon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_netifcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the name of the interface from a netifcon statement. * @param policy The policy associated wiht the netifcon statement. * @param ocon The netifcon statement from which to get the name. * @param name Pointer in which to store the interface name. The caller * should not free this string. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_netifcon_get_name(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const char **name); /** * Get the message context from a netifcon statement. * @param policy The policy associated with the netifcon statement. * @param ocon The netifcon statement from which to get the message context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_netifcon_get_msg_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context); /** * Get the interface context from a netifcon statement. * @param policy The policy associated with the netifcon statement. * @param ocon The netifcon statement from which to get the interface context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_netifcon_get_if_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_NETIFCON_QUERY_H */ setools-4.1.1/libqpol/include/qpol/nodecon_query.h000066400000000000000000000131661314142262400222760ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over nodecon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_NODECON_QUERY_H #define QPOL_NODECON_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #define QPOL_IPV4 0 #define QPOL_IPV6 1 typedef struct qpol_nodecon qpol_nodecon_t; /** * Get a single nodecon statement by address, mask and protocol. * @param policy The policy from which to get the nodecon statement. * @param addr The IP address of the node, if IPv4 only addr[0] is used. * @param mask The net mask of the node, if IPv4 only mask[0] is used. * @param protocol The protocol used in the address and mask; * set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6. * @param ocon Pointer in which to store the statement returned. * The caller should call free() to free memory used by this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_nodecon_by_node(const qpol_policy_t * policy, uint32_t addr[4], uint32_t mask[4], unsigned char protocol, qpol_nodecon_t ** ocon); /** * Get an iterator for the nodecon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_nodecon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. The caller must also call free() * on items returned by qpol_iterator_get_item() when using this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_nodecon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the IP address from a nodecon statement. Sets protocol to indicate * the number of integers used by the array. * @param policy The policy associated with the nodecon statement. * @param ocon The nodecon statement from which to get the IP address. * @param addr Pointer to the byte array of the IP addressto be set ; * the caller should not free this pointer. The number of integers * in this array is 1 if IPv4 and 4 if IPv6. * @param protocol Pointer to be set to the protocol value; this * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set, addr will be NULL, and protocol will be 0. */ extern int qpol_nodecon_get_addr(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** addr, unsigned char *protocol); /** * Get the net mask from a nodecon statement. Sets protocol to indicate * the number of integers used by the array. * @param policy The policy associated with the nodecon statement. * @param ocon The nodecon statement from which to get the net mask. * @param mask Pointer to the byte array of the net mask to be set; * the caller should not free this pointer. The number of integers * in this array is 1 if IPv4 and 4 if IPv6. * @param protocol Pointer to be set to the protocol value; this * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set, mask will be NULL, and protocol will be 0. */ extern int qpol_nodecon_get_mask(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** mask, unsigned char *protocol); /** * Get the protocol from a nodecon statement. * @param policy The policy associated with the nodecon statement. * @param ocon The nodecon statement from which to get the protocol. * @param protocol Pointer to be set to the protocol value; this * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and protocol will be 0. */ extern int qpol_nodecon_get_protocol(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, unsigned char *protocol); /** * Get the context from a nodecon statement. * @param policy The policy associated with the nodecon statement. * @param ocon The nodecon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_nodecon_get_context(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_NODECON_QUERY_H */ setools-4.1.1/libqpol/include/qpol/permissive_query.h000066400000000000000000000047041314142262400230350ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the permissive types. * * @author Steve Lawrence slawrence@tresys.com * * Copyright (C) 2006-2009 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_PERMISSIVE_QUERY_H #define QPOL_PERMISSIVE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_permissive qpol_permissive_t; /** * Get an iterator for the permissive types in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_permissive_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a permissive type from its datum. * @param policy The policy with which the permissive type is associated. * @param datum Permissive datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_permissive_get_name(const qpol_policy_t *policy, const qpol_permissive_t *datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_PERMISSIVE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/polcap_query.h000066400000000000000000000046521314142262400221270ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the policy capabilities * * @author Steve Lawrence slawrence@tresys.com * * Copyright (C) 2006-2009 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_POLCAP_QUERY_H #define QPOL_POLCAP_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_polcap qpol_polcap_t; /** * Get an iterator for the policay capabilities in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_isid_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_polcap_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the name which identifies a policy capability from its datum. * @param policy The policy with which the policy capability is associated. * @param datum Polcap datum for which to get the name. Must be non-NULL. * @param name Pointer to the string in which to store the name. * Must be non-NULL. The caller should not free the string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_polcap_get_name(const qpol_policy_t *policy, const qpol_polcap_t *datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_POLCAP_QUERY_H */ setools-4.1.1/libqpol/include/qpol/policy.h000066400000000000000000000266411314142262400207250ustar00rootroot00000000000000/** * @file * Defines the public interface the QPol policy. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * @author Brandon Whalen bwhalen@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_POLICY_H #define QPOL_POLICY_H #ifdef __cplusplus extern "C" { #endif #include #include typedef struct qpol_policy qpol_policy_t; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef void (__attribute__ ((format(printf, 4, 0))) *qpol_callback_fn_t) (void *varg, const struct qpol_policy * policy, int level, const char *fmt, va_list va_args); #define QPOL_POLICY_UNKNOWN -1 #define QPOL_POLICY_KERNEL_SOURCE 0 #define QPOL_POLICY_KERNEL_BINARY 1 #define QPOL_POLICY_MODULE_BINARY 2 /** * When loading the policy, do not load neverallow rules. */ #define QPOL_POLICY_OPTION_NO_NEVERALLOWS 0x00000001 /** * When loading the policy, do not load any rules; * this option implies QPOL_POLICY_OPTION_NO_NEVERALLOWS. */ #define QPOL_POLICY_OPTION_NO_RULES 0x00000002 /** * List of capabilities a policy may have. This list represents * features of policy that may differ from version to version or * based upon the format of the policy file. Note that "polcaps" in * this case refers to "policy capabilities" that were introduced * with version 22 policies. */ typedef enum qpol_capability { /** The policy format stores the names of attributes. */ QPOL_CAP_ATTRIB_NAMES, /** The policy format stores the syntactic rule type sets. */ QPOL_CAP_SYN_RULES, /** The policy format stores rule line numbers (implies QPOL_CAP_SYN_RULES). */ QPOL_CAP_LINE_NUMBERS, /** The policy version supports booleans and conditional statements. */ QPOL_CAP_CONDITIONALS, /** The policy version supports MLS components and statements. */ QPOL_CAP_MLS, /** The policy version has policy capabilities (polcaps). */ QPOL_CAP_POLCAPS, /** The policy format supports linking loadable modules. */ QPOL_CAP_MODULES, /** The policy was loaded with av/te rules. */ QPOL_CAP_RULES_LOADED, /** The policy source may be displayed. */ QPOL_CAP_SOURCE, /** The policy supports and was loaded with neverallow rules. */ QPOL_CAP_NEVERALLOW, /** The policy supports bounds rules. */ QPOL_CAP_BOUNDS, /** The policy supports default object rules. */ QPOL_CAP_DEFAULT_OBJECTS, QPOL_CAP_DEFAULT_TYPE, /** The policy supports permissive types. */ QPOL_CAP_PERMISSIVE, /** The policy supports filename type_transition rules. */ QPOL_CAP_FILENAME_TRANS, /** The policy supports role transition rules. */ QPOL_CAP_ROLETRANS, /** The policy supports ioctl extended permissions. */ QPOL_CAP_XPERM_IOCTL } qpol_capability_e; /** * Open a policy from a passed in file path. * @param filename The name of the file to open. * @param policy The policy to populate. The caller should not free * this pointer. * @param fn (Optional) If non-NULL, the callback to be used by the handle. * @param varg (Optional) The argument needed by the handle callback. * @param options Options to control loading only portions of a policy; * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above. * @return Returns one of QPOL_POLICY_KERNEL_SOURCE, * QPOL_POLICY_KERNEL_BINARY, or QPOL_POLICY_MODULE_BINARY on success * and < 0 on failure; if the call fails, errno will be set and * *policy will be NULL. */ extern int qpol_policy_open_from_file(const char *filename, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg, const int options); /** * Open a policy from a passed in file path but do not load any rules. * @param filename The name of the file to open. * @param policy The policy to populate. The caller should not free * this pointer. * @param fn (Optional) If non-NULL, the callback to be used by the handle. * @param varg (Optional) The argument needed by the handle callback. * @return Returns one of QPOL_POLICY_* above on success and < 0 on failure; * if the call fails, errno will be set and *policy will be NULL. * @deprecated use qpol_policy_open_from_file() with the option QPOL_POLICY_OPTION_NO_RULES instead. */ extern int qpol_policy_open_from_file_no_rules(const char *filename, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg) __attribute__ ((deprecated)); /** * Open a policy from a passed in buffer. * @param policy The policy to populate. The caller should not free * this pointer. * @param filedata The policy file stored in memory . * @param size The size of filedata * @param fn (Optional) If non-NULL, the callback to be used by the handle. * @param varg (Optional) The argument needed by the handle callback. * @param options Options to control loading only portions of a policy; * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *policy will be NULL. */ extern int qpol_policy_open_from_memory(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn, void *varg, const int options); /** * Close a policy and deallocate its memory. Does nothing if it is * already NULL. * @param policy Reference to the policy to close. The pointer will * be set to NULL afterwards. */ extern void qpol_policy_destroy(qpol_policy_t ** policy); /** * Re-evaluate all conditionals in the policy updating the state * and setting the appropriate rule list as emabled for each. * This call modifies the policy. * @param policy The policy for which to re-evaluate the conditionals. * This policy will be modified by this function. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set. On failure, the policy state may be inconsistent. */ extern int qpol_policy_reevaluate_conds(qpol_policy_t * policy); /** * Append a module to a policy. The policy now owns the module. * Note that the caller must still invoke qpol_policy_rebuild() * to update the policy. * @param policy The policy to which to add the module. * @param module The module to append. The caller should not * destroy this module if this function succeeds. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and both the policy and the module will * remain unchanged. If the call fails, the caller is still * responsible for calling qpol_module_destroy(). */ extern int qpol_policy_append_module(qpol_policy_t * policy, qpol_module_t * module); /** * Rebuild the policy. If the options provided are the same as those * provied to the last call to rebuild or open and the modules were not * changed, this function does nothing; otherwise, re-link all enabled * modules with the base and then call expand. If the syntactic rule * table was previously built, the caller should call * qpol_policy_build_syn_rule_table() after calling this function. * @param policy The policy to rebuild. * This policy will be altered by this function. * @param options Options to control loading only portions of a policy; * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and the policy will be reverted to its previous state. */ extern int qpol_policy_rebuild(qpol_policy_t * policy, const int options); /** * Get an iterator of all modules in a policy. * @param policy The policy from which to get the iterator. * @param iter Iteraror of modules (of type qpol_module_t) returned. * The caller should not destroy the modules returned by * qpol_iterator_get_item(). * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_module_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the version number of the policy. * @param policy The policy for which to get the version. * @param version Pointer to the integer to set to the version number. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *version will be 0. */ extern int qpol_policy_get_policy_version(const qpol_policy_t * policy, unsigned int *version); /** * Get the type of policy (source, binary, or module). * @param policy The policy from which to get the type. * @param type Pointer to the integer in which to store the type. * Value will be one of QPOL_POLICY_* from above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *type will be QPOL_POLICY_UNKNOWN. */ extern int qpol_policy_get_type(const qpol_policy_t * policy, int *type); /** * Determine if a policy has support for a specific capability. * @param policy The policy to check. * @param cap The capability for which to check. Must be one of QPOL_CAP_* * defined above. * @return Non-zero if the policy has the specified capability, and zero otherwise. */ extern int qpol_policy_has_capability(const qpol_policy_t * policy, qpol_capability_e cap); /** * Get the handle_unknown classes/perms flag for the policy. * @param policy The policy for which to get the version. * @param handle_unknown Pointer to the integer to set to the version number. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *handle_unknown will be 0. */ extern int qpol_policy_get_policy_handle_unknown(const qpol_policy_t * policy, unsigned int *handle_unknown); /** * Get target platform (SELinux or XEN) of the policy. * @param policy The policy for which to get the target. * @param target_platform Pointer to the target. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *target_platform will be 0. */ extern int qpol_policy_get_target_platform(const qpol_policy_t *policy, int *target_platform); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/include/qpol/policy_extend.h000066400000000000000000000061701314142262400222670ustar00rootroot00000000000000/** * @file * Public interface for loading and using an extended * policy image. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_POLICY_EXTEND_H #define QPOL_POLICY_EXTEND_H #ifdef __cplusplus extern "C" { #endif #include #include /** * Build the table of syntactic rules for a policy. * Subsequent calls to this function have no effect. * @param policy The policy for which to build the table. * This policy will be modified by this call. * @return 0 on success and < 0 on error; if the call fails, * errno will be set. */ extern int qpol_policy_build_syn_rule_table(qpol_policy_t * policy); /* forward declarations: see avrule_query.h and terule_query.h */ struct qpol_avrule; struct qpol_terule; /** * Get an iterator over the syntactic rules contributing to an av rule. * @param policy Policy associated with the rule. * @param rule Rule from which to get the syntactic rules. * @param iter Iterator over items of type qpol_syn_avrule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_avrule_get_syn_avrule_iter(const qpol_policy_t * policy, const struct qpol_avrule *rule, qpol_iterator_t ** iter); /** * Get an iterator over the syntactic rules contributing to a type rule. * @param policy Policy associated with the rule. * @param rule Rule from which to get the syntactic rules. * @param iter Iterator over items of type qpol_syn_terule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_terule_get_syn_terule_iter(const qpol_policy_t * policy, const struct qpol_terule *rule, qpol_iterator_t ** iter); #ifdef __cplusplus } #endif #endif /* QPOL_POLICY_EXTEND_H */ setools-4.1.1/libqpol/include/qpol/portcon_query.h000066400000000000000000000113761314142262400223360ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over portcon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_PORTCON_QUERY_H #define QPOL_PORTCON_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include typedef struct qpol_portcon qpol_portcon_t; /** * Get a single portcon statement by port range and protocol. * @param policy The policy from which to get the portcon statement. * @param low The low port of the range of ports (or single port). * @param high The high port of the range of ports; if searching for a * single port, set high equal to low. * @param protocol The protocol used in the portcon statement. * Value should be one of IPPROTO_TCP or IPPROTO_UDP from netinet/in.h * @param ocon Pointer in which to store the statement returned. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_portcon_by_port(const qpol_policy_t * policy, uint16_t low, uint16_t high, uint8_t protocol, const qpol_portcon_t ** ocon); /** * Get an iterator for the portcon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_portcon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_portcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the protocol from a portcon statement. * @param policy The policy associated with the portcon statement. * @param ocon The portcon statement from which to get the protocol. * @param protocol Pointer to set to the value of protocol. * Value will be one of IPPROTO_TCP or IPPROTO_UDP from netinet/in.h * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *protocol will be 0; */ extern int qpol_portcon_get_protocol(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint8_t * protocol); /** * Get the low port from a portcon statement. * @param policy the policy associated with the portcon statement. * @param ocon The portcon statement from which to get the low port. * @param port Pointer to set to the port number. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *port will be 0. */ extern int qpol_portcon_get_low_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port); /** * Get the high port from a portcon statement. * @param policy the policy associated with the portcon statement. * @param ocon The portcon statement from which to get the high port. * @param port Pointer to set to the port number. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *port will be 0. */ extern int qpol_portcon_get_high_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port); /** * Get the context from a portcon statement. * @param policy the policy associated with the portcon statement. * @param ocon The portcon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_portcon_get_context(const qpol_policy_t * policy, const qpol_portcon_t * ocon, const qpol_context_t ** context); #ifdef __cplusplus } #endif #endif /* QPOL_PORTCON_QUERY_H */ setools-4.1.1/libqpol/include/qpol/rbacrule_query.h000066400000000000000000000132221314142262400224410ustar00rootroot00000000000000/** * @file * Defines public interface for iterating over RBAC rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_RBACRULE_QUERY #define QPOL_RBACRULE_QUERY #ifdef __cplusplus extern "C" { #endif #include #include typedef struct qpol_role_allow qpol_role_allow_t; typedef struct qpol_role_trans qpol_role_trans_t; /** * Get an iterator over all role allow rules in the policy. * @param policy Policy from which to create the iterator. * @param iter Iterator over items of type qpol_role_allow_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_role_allow_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the source role from a role allow rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the source role. * @param source Pointer in which to store the source role. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_role_allow_get_source_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** source); /** * Get the target role from a role allow rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the target role. * @param target Pointer in which to store the target role. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_role_allow_get_target_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** target); /** * Get an iterator over all role transition rules in the policy. * @param policy Policy from which to create the iterator. * @param iter Iterator over items of type qpol_role_trans_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_role_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the source role from a role transition rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the source role. * @param source Pointer in which to store the source role. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_role_trans_get_source_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** source); /** * Get the target type from a role transition rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the target type. * @param target Pointer in which to store the target type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_role_trans_get_target_type(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_type_t ** target); /** * Get the object class from a role transition rule. * @param rule The rule from which to get the object class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_role_trans_get_object_class(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_class_t ** obj_class); /** * Get the default role from a role transition rule. * @param policy The policy from which the rule comes. * @param rule The rule from which to get the default role. * @param dflt Pointer in which to store the default role. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *dflt will be NULL. */ extern int qpol_role_trans_get_default_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** dflt); #ifdef __cplusplus } #endif #endif /* QPOL_RBACRULE_QUERY */ setools-4.1.1/libqpol/include/qpol/role_query.h000066400000000000000000000115061314142262400216060ustar00rootroot00000000000000 /** * @file * Defines the public interface for searching and iterating over roles. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_ROLE_QUERY_H #define QPOL_ROLE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_role qpol_role_t; /** * Get the datum for a role by name. * @param policy The policy from which to get the role. * @param name The name of the role; searching is case sensitive. * @param datum Pointer in which to store the role datum; the caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *datum will be NULL. */ extern int qpol_policy_get_role_by_name(const qpol_policy_t * policy, const char *name, const qpol_role_t ** datum); /** * Get an iterator for roles declared in the policy. * @param policy The policy with which to create the iterator. * @param iter Iterator of type qpol_role_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator * is valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_role_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a role; values range from * 1 to the number of declared roles. * @param policy The policy associated with the role. * @param datum The role from which to get the value. * @param value Pointer to the integer to set to value. Must be non-NULL. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and value will be 0. */ extern int qpol_role_get_value(const qpol_policy_t * policy, const qpol_role_t * datum, uint32_t * value); /** * Get an iterator for the set of roles dominated by a role. * @param policy The policy associated with the role. * @param datum The role from which to get the dominated roles. * @param dominates Iterator of type qpol_role_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. Note: By * convention a role always dominates itself, so the user of this * iterator should always check for this case. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *dominates will be NULL. */ extern int qpol_role_get_dominate_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** dominates); /** * Get an iterator for the set of types assigned to a role. * @param policy The policy associated with the role. * @param datum The role from which to get the types. * @param types Iterator of type qpol_type_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator * is valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and types will be NULL. */ extern int qpol_role_get_type_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** types); /** * Get the name by which a role is identified from its datum. * @param policy The policy associated with the role. * @param datum The role for which to get the name. * @param name Pointer in which to store the name; the caller * should not free this string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_role_get_name(const qpol_policy_t * policy, const qpol_role_t * datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_ROLE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/syn_rule_query.h000066400000000000000000000324451314142262400225120ustar00rootroot00000000000000/** * @file * Public interface for querying syntactic rules from the extended * policy image. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_SYN_RULE_QUERY_H #define QPOL_SYN_RULE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_type_set qpol_type_set_t; typedef struct qpol_syn_avrule qpol_syn_avrule_t; typedef struct qpol_syn_terule qpol_syn_terule_t; /** * Get an iterator of the included types in a type set. * @param policy Policy associated with the type set. * @param ts Type set from which to get the included types. * @param iter Iterator over items of type qpol_type_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_type_set_get_included_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter); /** * Get an iterator of the subtracted types in a type set. * @param policy Policy associated with the type set. * @param ts Type set from which to get the subtracted types. * @param iter Iterator over items of type qpol_type_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_type_set_get_subtracted_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter); /** * Determine if a type set includes '*'. * @param policy Policy associated with the type set. * @param ts Type set to check for '*'. * @param is_star Pointer to integer to set. * Will be set to 1 if ts contains '*' or 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_star will be 0. */ extern int qpol_type_set_get_is_star(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_star); /** * Determine if a type set is complemented (contains '~'). * @param policy Policy associated with the type set. * @param ts Type set to check for complement. * @param is_comp Pointer to integer to set. * Will be set to 1 if ts is complemented or 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_comp will be 0. */ extern int qpol_type_set_get_is_comp(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_comp); /** * Get the rule type of a syntactic avrule. * @param policy Policy associated with the rule. * @param rule Avrule from which to get the type. * @param rule_type Pointer to integer to set. * Will be one of QPOL_RULE_* (see qpol/avrule_query.h). * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *rule_type will be 0. */ extern int qpol_syn_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * rule_type); /** * Get the set of types specified for a syntatic rule's source field. * @param policy Policy associated with the rule. * @param rule Avrule from which to get the source type set. * @param source_set Type set returned; the caller should not * free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source_set will be NULL. */ extern int qpol_syn_avrule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, const qpol_type_set_t ** source_set); /** * Get the set of types specified for a syntactic rule's target field. * @param policy Policy associated with the rule. * @param rule Avrule from which to get the target type set. * @param target_set Type set returned; the caller should not * free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target_set will be NULL. */ extern int qpol_syn_avrule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, const qpol_type_set_t ** target_set); /** * Determine if a syntactic rule includes the self flag in the target set. * @param policy Policy associated with the rule. * @param rule Avrule to check for the self flag. * @param is_self Pointer to the integer to set; if the rule includes self, * this will be set to 1, otherwise it will be set to 0. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_self will be 0. */ extern int qpol_syn_avrule_get_is_target_self(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_self); /** * Get an iterator over all classes specified in a syntactic rule. * @param policy Policy associated with the rule. * @param rule The rule from which to get the classes. * @param classes Iterator over items of type qpol_class_t* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *classes will be NULL. */ extern int qpol_syn_avrule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** classes); /** * Get an iterator over all permissions specified in a syntactic rule. * @param policy Policy associated with the * @param rule The rule from which to get the permissions. * @param perms Iterator over items of type char* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *perms will be NULL. */ extern int qpol_syn_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** perms); /** * Get the line number of a syntactic rule. * @param policy Policy associated with the rule * @param rule The rule for which to get the line number. * @param lineno Pointer to set to the line number. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_avrule_get_lineno(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, unsigned long *lineno); /** * If the syntactic rule is within a conditional, then get that * conditional and assign it to cond. Otherwise assign to cond NULL. * @param policy Policy associated with the rule. * @param rule The rule for which to get the conditional. * @param cond Reference pointer to this rule's conditional * expression, or NULL if the rule is unconditional. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_avrule_get_cond(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, const qpol_cond_t ** cond); /** * Determine if the syntactic rule is enabled. Unconditional rules * are always enabled. * @param policy Policy associated with the rule. * @param rule The rule for which to get the conditional. * @param is_enabled Integer in which to store the result: set to 1 * if enabled and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_enabled); /** * Get the rule type of a syntactic terule. * @param policy Policy associated with the rule. * @param rule Terule from which to get the type. * @param rule_type Pointer to integer to set. * Will be one of QPOL_RULE_TYPE_* (see qpol/terule_query.h). * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *rule_type will be 0. */ extern int qpol_syn_terule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * rule_type); /** * Bet the set of types specified for a syntactic rule's source field. * @param policy Policy associated with the rule. * @param rule Terule from which to get the source type set. * @param source_set Type set returned; the caller shoule not * free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source_set will be NULL. */ extern int qpol_syn_terule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_type_set_t ** source_set); /** * Get the set of types specified for a syntactic rule's target field. * @param policy Policy associated with the rule. * @param rule Terule from which to get the target types et. * @param target_set Type set returned; ther caller should not * free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target_set will be NULL. */ extern int qpol_syn_terule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_type_set_t ** target_set); /** * Get an iterator over all classes specified in a syntactic rule. * @param policy Policy associated with the rule. * @param rule The rule from which to get the classes. * @param classes Iterator over items of type qpol_class_t* returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *classes will be NULL. */ extern int qpol_syn_terule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, qpol_iterator_t ** classes); /* forward declaration */ struct qpol_type; /** * Get the default type of a syntactic terule. * @param policy Policy associated with the rule. * @param rule Terule from which to et the default type. * @param dflt Reference pointer to the type to return. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *dflt will be NULL. */ extern int qpol_syn_terule_get_default_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const struct qpol_type **dflt); /** * Get the line number of a syntactic rule. * @param policy Policy associated with the rule. * @param rule The rule for which to get the line number. * @param lineno Pointer to set to the line number. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_terule_get_lineno(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, unsigned long *lineno); /** * If the syntactic rule is within a conditional, then get that * conditional and assign it to cond. Otherwise assign to cond NULL. * @param policy Policy associated with the rule. * @param rule The rule for which to get the conditional. * @param cond Reference pointer to this rule's conditional * expression, or NULL if the rule is unconditional. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_terule_get_cond(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_cond_t ** cond); /** * Determine if the syntactic rule is enabled. Unconditional rules * are always enabled. * @param policy Policy associated with the rule. * @param rule The rule for which to get the conditional. * @param is_enabled Integer in which to store the result: set to 1 * if enabled and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *lineno will be 0. */ extern int qpol_syn_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * is_enabled); #ifdef __cplusplus } #endif #endif /* QPOL_SYN_RULE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/terule_query.h000066400000000000000000000150111314142262400221400ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over type rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_TERULE_QUERY_H #define QPOL_TERULE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include typedef struct qpol_terule qpol_terule_t; /* rule type defines (values copied from "sepol/policydb/policydb.h") */ #define QPOL_RULE_TYPE_TRANS 16 #define QPOL_RULE_TYPE_CHANGE 64 #define QPOL_RULE_TYPE_MEMBER 32 /** * Get an iterator over all type rules in a policy of a rule type in * rule_type_mask. It is an error to call this function if rules are not * loaded. * @param policy Policy from which to get the av rules. * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values. * It is an error to specify any other values of QPOL_RULE_* in the mask. * @param iter Iterator over items of type qpol_terule_t returned. * The caller is responsible for calling qpol_iterator_destroy() * to free memory used by this iterator. * It is important to note that this iterator is only valid as long as * the policy is unmodifed. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_terule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter); /** * Get the source type from a type rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the source type. * @param source Pointer in which to store the source type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *source will be NULL. */ extern int qpol_terule_get_source_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** source); /** * Get the target type from a type rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the target type. * @param target Pointer in which to store the target type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *target will be NULL. */ extern int qpol_terule_get_target_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** target); /** * Get the object class from a type rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the object class. * @param obj_class Pointer in which to store the object class. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *obj_class will be NULL. */ extern int qpol_terule_get_object_class(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_class_t ** obj_class); /** * Get the default type from a type rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the default type. * @param dflt Pointer in which to store the default type. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *dflt will be NULL. */ extern int qpol_terule_get_default_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** dflt); /** * Get the rule type value for a type rule. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the rule type. * @param rule_type Integer in which to store the rule type value. * The value will be one of the QPOL_RULE_* values above. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *rule_type will be 0. */ extern int qpol_terule_get_rule_type(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * rule_type); /** * Get the conditional from which a type rule comes. If the rule * is not a conditional rule *cond is set to NULL. * @param policy Policy from which the rule comes. * @param rule The rule from which to get the conditional. * @param cond The conditional returned. (NULL if rule is not conditional) * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *cond will be NULL. If the rule is not conditional * *cond is set to NULL and the function is considered successful. */ extern int qpol_terule_get_cond(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_cond_t ** cond); /** * Determine if a rule is enabled. Unconditional rules are always enabled. * @param policy Policy from which the rule comes. * @param rule The rule to check. * @param is_enabled Integer in which to store the result: set to 1 if enabled * and 0 otherwise. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *is_enabled will be 0. */ extern int qpol_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * is_enabled); /** * Get the list (true or false) in which a conditional rule is. It is * an error to call this function for an unconditional rule. * @param policy Policy from which the rule comes. * @param rule The rule to check. * @param which_list Integer in which to store the result: set to 1 if * rule is in the true list or 0 if in the false list. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *which_list will be 0. */ extern int qpol_terule_get_which_list(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * which_list); #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/include/qpol/type_query.h000066400000000000000000000166521314142262400216350ustar00rootroot00000000000000 /** * @file * Defines the public interface for searching and iterating over types. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_TYPE_QUERY_H #define QPOL_TYPE_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_type qpol_type_t; /** * Get the datum for a type by name. * @param policy The policy from which to get the type. * @param name The name of the type; searching is case sensitive. * @param datum Pointer in which to store the type datum; the caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *datum will be NULL. */ extern int qpol_policy_get_type_by_name(const qpol_policy_t * policy, const char *name, const qpol_type_t ** datum); /** * Get an iterator for types (including attributes and aliases) * declared in the policy. * @param policy The policy from which to create the iterator. * @param iter Iterator of type qpol_type_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_type_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a type. Values range from 1 * to the number of types declared in the policy. * @param policy The policy associated with the type. * @param datum The type from which to get the value. * @param value Pointer to the integer in which to store value. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and value will be 0. */ extern int qpol_type_get_value(const qpol_policy_t * policy, const qpol_type_t * datum, uint32_t * value); /** * Determine whether a given type is an alias for another type. * @param policy The policy associated with the type. * @param datum The type to check. * @param isalias Pointer to be set to 1 (true) if the type is an alias * and 0 (false) otherwise. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *isalias will be 0 (false). */ extern int qpol_type_get_isalias(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isalias); /** * Determine whether a given type is an attribute. * @param policy The policy associated with the type. * @param datum The type to check. * @param isattr Pointer to be set to 1 (true) if the type is an * attribute and 0 (false) otherwise. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *isattr will be 0 (false). */ extern int qpol_type_get_isattr(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isattr); /** * Determine whether a given type has been marked as enforcing * (default) or as permissive. If the policy does not support * permissive types, then all types are enforcing. Attributes are * always enforcing. * * @param policy The policy associated with the type. * @param datum The type to check. * @param ispermissive Pointer to be set to 1 (true) if the type is * permissive and 0 (false) otherwise. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *ispermissive will be 0 (false). */ extern int qpol_type_get_ispermissive(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *ispermissive); /** * Get an iterator for the list of types in an attribute. * @param policy The policy associated with the attribute. * @param datum The attribute from which to get the types. * @param types Iterator of type qpol_type_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. * @return Returns 0 on success, > 0 if the type is not an attribute * and < 0 on failure; if the call fails, errno will be set and * *types will be NULL. If the type is not an attribute *types will * be NULL. */ extern int qpol_type_get_type_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** types); /** * Get an iterator for the list of attributes given to a type. * @param policy The policy associated with the type. * @param datum The type for which to get the attributes. * @param attrs Iterator of type qpol_type_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. * @return Returns 0 on success, > 0 if the type is an attribute * and < 0 on failure; if the call fails, errno will be set and * *types will be NULL. If the type is an attribute *types will * be NULL. */ extern int qpol_type_get_attr_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** attrs); /** * Get the name by which a type is identified from its datum. * @param policy The policy associated with the type. * @param datum The type for which to get the name. * @param name Pointer in which to store the name; the caller * should not free the string. If the type is an alias then the * primary name will be returned. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_type_get_name(const qpol_policy_t * policy, const qpol_type_t * datum, const char **name); /** * Get an iterator for the list of aliases for a type. If the given * type is an alias, this returns an iterator of its primary type's * aliases. * @param policy The policy associated with the type. * @param datum The type for which to get aliases. * @param aliases Iterator of type char* returned; the caller is * responsible for calling qpol_iterator_destroy to free * memory used; it is important to note that the iterator is valid * only as long as the policy is unchanged. If a type has no aliases, * the iterator will be at end and have size 0. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *aliases will be NULL. */ extern int qpol_type_get_alias_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** aliases); #ifdef __cplusplus } #endif #endif /* QPOL_TYPE_QUERY_H */ setools-4.1.1/libqpol/include/qpol/user_query.h000066400000000000000000000124031314142262400216200ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over users. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_USER_QUERY_H #define QPOL_USER_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include typedef struct qpol_user qpol_user_t; /** * Get the datum for a user by name. * @param policy The policy from which to get the user. * @param name The name of the user; searching is case sensitive. * @param datum Pointer in which to store the user datum; the caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and and *datum will be NULL. */ extern int qpol_policy_get_user_by_name(const qpol_policy_t * policy, const char *name, const qpol_user_t ** datum); /** * Get an iterator for users declared in the policy. * @param policy The policy from which to create the iterator. * @param iter Iterator of type qpol_user_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_user_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); /** * Get the integer value associated with a user. Values range from 1 to * the number of users declared in the policy. * @param policy The policy associate with the user. * @param datum The user from which to get the value. * @param value Pointer to the integer to set to value. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and value will be 0. */ extern int qpol_user_get_value(const qpol_policy_t * policy, const qpol_user_t * datum, uint32_t * value); /** * Get an iterator for the set of roles assigned to a user. * @param policy The policy associated with the user. * @param datum The user from which to get the roles. * @param roles Iterator of type qpol_role_t* returned; * the caller is responsible for calling qpol_iterator_destroy to * free memory used; it is important to note that the iterator is * valid only as long as the policy is unchanged. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *roles will be NULL. */ extern int qpol_user_get_role_iter(const qpol_policy_t * policy, const qpol_user_t * datum, qpol_iterator_t ** roles); /** * Get the allowed MLS range of a user. If the policy is not MLS * then the returned level will be NULL. * @param policy The policy associated with the user. * @param datum The user from which to get the range. * @param range Pointer in which to store the range. If the policy * is not MLS then NULL will be assigned to the pointer. The caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *range will be NULL. */ extern int qpol_user_get_range(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_range_t ** range); /** * Get the default level for a user. If the policy is not MLS then * the returned level will be NULL. * @param policy The policy associated with the user. * @param datum The user from which to get the level. * @param level Pointer in which to store the level. If the policy * is not MLS then NULL will be assigned to the pointer. The caller * should not free this pointer. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *level will be NULL. */ extern int qpol_user_get_dfltlevel(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_level_t ** level); /** * Get the name which identifies a user from its datum. * @param policy The policy associated with the user. * @param datum The user for which to get the name. * @param name Pointer in which to store the name; the caller * should not free this string. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set and *name will be NULL. */ extern int qpol_user_get_name(const qpol_policy_t * policy, const qpol_user_t * datum, const char **name); #ifdef __cplusplus } #endif #endif /* QPOL_USER_QUERY_H */ setools-4.1.1/libqpol/include/qpol/xen_query.h000066400000000000000000000300701314142262400214340ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * Xen statements. * * @author Richard Haines richard_c_haines@btinternet.com * Derived from portcon_query.h * * 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. */ #ifndef QPOL_XEN_QUERY_H #define QPOL_XEN_QUERY_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct qpol_iomemcon qpol_iomemcon_t; typedef struct qpol_ioportcon qpol_ioportcon_t; typedef struct qpol_pcidevicecon qpol_pcidevicecon_t; typedef struct qpol_pirqcon qpol_pirqcon_t; typedef struct qpol_devicetreecon qpol_devicetreecon_t; /******************************* iomemcon **************************/ /** * Get a single iomemcon statement by range. * @param policy The policy from which to get the iomemcon statement. * @param low The low addr of the range of addrs (or single addr). * @param high The high addr of the range of addrs; if searching for a * single addr, set high equal to low. * @param ocon Pointer in which to store the statement returned. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_iomemcon_by_addr( const qpol_policy_t *policy, uint64_t low, uint64_t high, const qpol_iomemcon_t **ocon); /** * Get an iterator for the iomemcon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_iomemcon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_iomemcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the low addr from a iomemcon statement. * @param policy the policy associated with the iomemcon statement. * @param ocon The iomemcon statement from which to get the low addr. * @param addr Pointer to set to the addr. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *addr will be 0. */ extern int qpol_iomemcon_get_low_addr(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, uint64_t *addr); /** * Get the high addr from a iomemcon statement. * @param policy the policy associated with the iomemcon statement. * @param ocon The iomemcon statement from which to get the high addr. * @param addr Pointer to set to the addr. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *addr will be 0. */ extern int qpol_iomemcon_get_high_addr(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, uint64_t *addr); /** * Get the context from a iomemcon statement. * @param policy the policy associated with the iomemcon statement. * @param ocon The iomemcon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_iomemcon_get_context(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, const qpol_context_t **context); /******************************* ioportcon **************************/ /** * Get a single ioportcon statement by range. * @param policy The policy from which to get the ioportcon statement. * @param low The low port of the range of ports (or single port). * @param high The high port of the range of ports; if searching for a * single port, set high equal to low. * @param ocon Pointer in which to store the statement returned. * The caller should not free this pointer. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *ocon will be NULL. */ extern int qpol_policy_get_ioportcon_by_port( const qpol_policy_t *policy, uint32_t low, uint32_t high, const qpol_ioportcon_t **ocon); /** * Get an iterator for the ioportcon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_ioportcon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_ioportcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the low port from a ioportcon statement. * @param policy the policy associated with the ioportcon statement. * @param ocon The ioportcon statement from which to get the low port. * @param port Pointer to set to the port. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *port will be 0. */ extern int qpol_ioportcon_get_low_port(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, uint32_t *port); /** * Get the high port from a ioportcon statement. * @param policy the policy associated with the ioportcon statement. * @param ocon The ioportcon statement from which to get the high port. * @param port Pointer to set to the port. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *port will be 0.32 */ extern int qpol_ioportcon_get_high_port(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, uint32_t *port); /** * Get the context from a ioportcon statement. * @param policy the policy associated with the ioportcon statement. * @param ocon The ioportcon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_ioportcon_get_context(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, const qpol_context_t **context); /******************************* pcidevicecon **************************/ /** * Get an iterator for the pcidevicecon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_pcidevicecon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_pcidevicecon_iter( const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the device id from a pcidevicecon statement. * @param policy the policy associated with the pcidevicecon statement. * @param ocon The pcidevicecon statement from which to get the low addr. * @param device Pointer to set to the device. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *device will be 0. */ extern int qpol_pcidevicecon_get_device(const qpol_policy_t *policy, const qpol_pcidevicecon_t *ocon, uint32_t *device); /** * Get the context from a pcidevicecon statement. * @param policy the policy associated with the pcidevicecon statement. * @param ocon The pcidevicecon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_pcidevicecon_get_context(const qpol_policy_t *policy, const qpol_pcidevicecon_t *ocon, const qpol_context_t **context); /************************* pirqcon *******************************/ /** * Get an iterator for the pirqcon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_pirqcon_t returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_pirqcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the irq id from a pirqcon statement. * @param policy the policy associated with the pirqcon statement. * @param ocon The pirqcon statement from which to get the irq. * @param irq Pointer to set to the irq. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *irq will be 0. */ extern int qpol_pirqcon_get_irq(const qpol_policy_t *policy, const qpol_pirqcon_t *ocon, uint16_t *irq); /** * Get the context from a pirqcon statement. * @param policy the policy associated with the pirqcon statement. * @param ocon The pirqcon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_pirqcon_get_context(const qpol_policy_t *policy, const qpol_pirqcon_t *ocon, const qpol_context_t **context); /************************* devicetreecon *******************************/ /** * Get an iterator for the devicetreecon statements in a policy. * @param policy The policy from which to create the iterator. * @param iter Iterator over items of type qpol_devicetreecon returned. * The caller is responsible for calling qpol_iterator_destroy * to free memory used by this iterator. * It is important to note that this iterator is only valid as long * as the policy is unmodified. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set and *iter will be NULL. */ extern int qpol_policy_get_devicetreecon_iter( const qpol_policy_t *policy, qpol_iterator_t **iter); /** * Get the path from a devicetreecon statement. * @param policy the policy associated with the devicetreecon statement. * @param ocon The devicetreecon statement from which to get the path. * @param path Pointer to set to the path. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *path will be 0. */ extern int qpol_devicetreecon_get_path(const qpol_policy_t *policy, const qpol_devicetreecon_t *ocon, char **path); /** * Get the context from a devicetreecon statement. * @param policy the policy associated with the devicetreecon statement. * @param ocon The devicetreecon statement from which to get the context. * @param context Pointer in which to store the context. * The caller should not free this pointer. * @return 0 on success < 0 on failure; if the call fails, * errno will be set and *context will be NULL. */ extern int qpol_devicetreecon_get_context(const qpol_policy_t *policy, const qpol_devicetreecon_t *ocon, const qpol_context_t **context); #ifdef __cplusplus } #endif #endif /* QPOL_XEN_QUERY_H */ setools-4.1.1/libqpol/isid_query.c000066400000000000000000000067261314142262400172020ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over initial SIDs. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_policy_get_isid_by_name(const qpol_policy_t * policy, const char *name, const qpol_isid_t ** ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || name == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_ISID]; tmp; tmp = tmp->next) { if (!strcmp(name, tmp->u.name)) break; } *ocon = (qpol_isid_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find initial SID statement for %s", name); errno = EINVAL; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_isid_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; ocon_state_t *os = NULL; int error = 0; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_ISID]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_isid_get_name(const qpol_policy_t * policy, const qpol_isid_t * ocon, const char **name) { ocontext_t *internal_ocon = NULL; if (name != NULL) *name = NULL; if (policy == NULL || ocon == NULL || name == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *name = internal_ocon->u.name; return STATUS_SUCCESS; } int qpol_isid_get_context(const qpol_policy_t * policy, const qpol_isid_t * ocon, const qpol_context_t ** context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) & (internal_ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/libqpol/iterator.c000066400000000000000000000503551314142262400166530ustar00rootroot00000000000000/** * @file * Contains the implementation of the qpol_iterator API, both * public and private, for returning lists of components and rules * from the policy database. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" /** * Declaration of qpol_iterator, an arbitrary valued policy component * iterator used to return lists of components. * */ struct qpol_iterator { policydb_t *policy; void *state; void *(*get_cur) (const qpol_iterator_t * iter); int (*next) (qpol_iterator_t * iter); int (*end) (const qpol_iterator_t * iter); size_t(*size) (const qpol_iterator_t * iter); void (*free_fn) (void *x); }; /** * The number of buckets in sepol's av tables was statically set in * libsepol < 2.0.20. With libsepol 2.0.20, this size was dynamically * calculated based upon the number of rules. */ static uint32_t iterator_get_avtab_size(const avtab_t * avtab) { #ifdef SEPOL_DYNAMIC_AVTAB return avtab->nslot; #else return AVTAB_SIZE; #endif } int qpol_iterator_create(const qpol_policy_t * policy, void *state, void *(*get_cur) (const qpol_iterator_t * iter), int (*next) (qpol_iterator_t * iter), int (*end) (const qpol_iterator_t * iter), size_t(*size) (const qpol_iterator_t * iter), void (*free_fn) (void *x), qpol_iterator_t ** iter) { int error = 0; if (iter != NULL) *iter = NULL; if (policy == NULL || state == NULL || iter == NULL || get_cur == NULL || next == NULL || end == NULL || size == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *iter = calloc(1, sizeof(struct qpol_iterator)); if (*iter == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } (*iter)->policy = &policy->p->p; (*iter)->state = state; (*iter)->get_cur = get_cur; (*iter)->next = next; (*iter)->end = end; (*iter)->size = size; (*iter)->free_fn = free_fn; return STATUS_SUCCESS; } void *qpol_iterator_state(const qpol_iterator_t * iter) { if (iter == NULL || iter->state == NULL) { errno = EINVAL; return NULL; } return iter->state; } const policydb_t *qpol_iterator_policy(const qpol_iterator_t * iter) { if (iter == NULL || iter->policy == NULL) { errno = EINVAL; return NULL; } return iter->policy; } void *hash_state_get_cur(const qpol_iterator_t * iter) { hash_state_t *hs = NULL; if (iter == NULL || iter->state == NULL || hash_state_end(iter)) { errno = EINVAL; return NULL; } hs = (hash_state_t *) iter->state; return hs->node->datum; } void *hash_state_get_cur_key(const qpol_iterator_t * iter) { hash_state_t *hs = NULL; if (iter == NULL || iter->state == NULL || hash_state_end(iter)) { errno = EINVAL; return NULL; } hs = (hash_state_t *) iter->state; return hs->node->key; } void *ocon_state_get_cur(const qpol_iterator_t * iter) { ocon_state_t *os = NULL; if (iter == NULL || iter->state == NULL || ocon_state_end(iter)) { errno = EINVAL; return NULL; } os = (ocon_state_t *) iter->state; return os->cur; } void *avtab_state_get_cur(const qpol_iterator_t * iter) { avtab_state_t *state; if (iter == NULL || iter->state == NULL || avtab_state_end(iter)) { errno = EINVAL; return NULL; } state = (avtab_state_t *) iter->state; return state->node; } int hash_state_next(qpol_iterator_t * iter) { hash_state_t *hs = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (hash_state_t *) iter->state; if (hs->table == NULL || *(hs->table) == NULL || hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } if (hs->node != NULL && hs->node->next != NULL) { hs->node = hs->node->next; } else { do { hs->bucket++; if (hs->bucket < (*(hs->table))->size) { hs->node = (*(hs->table))->htable[hs->bucket]; } else { hs->node = NULL; } } while (hs->bucket < (*(hs->table))->size && hs->node == NULL); } return STATUS_SUCCESS; } int ebitmap_state_next(qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } es = (ebitmap_state_t *) iter->state; if (es->cur >= es->bmap->highbit) { errno = ERANGE; return STATUS_ERR; } do { es->cur++; } while (es->cur < es->bmap->highbit && !ebitmap_get_bit(es->bmap, es->cur)); return STATUS_SUCCESS; } int ocon_state_next(qpol_iterator_t * iter) { ocon_state_t *os = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } os = (ocon_state_t *) iter->state; if (os->cur == NULL) { errno = ERANGE; return STATUS_ERR; } os->cur = os->cur->next; return STATUS_SUCCESS; } int avtab_state_next(qpol_iterator_t * iter) { avtab_t *avtab; avtab_state_t *state; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } state = iter->state; avtab = (state->which == QPOL_AVTAB_STATE_AV ? state->ucond_tab : state->cond_tab); if ((!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) && state->which == QPOL_AVTAB_STATE_COND) { errno = ERANGE; return STATUS_ERR; } do { if (state->node != NULL && state->node->next != NULL) { state->node = state->node->next; } else { /* find the next bucket */ do { state->bucket++; if (!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) { if (state->which == QPOL_AVTAB_STATE_AV) { state->bucket = 0; avtab = state->cond_tab; state->which = QPOL_AVTAB_STATE_COND; } else { state->node = NULL; break; } } if (avtab->htable && avtab->htable[state->bucket] != NULL) { state->node = avtab->htable[state->bucket]; break; } } while (avtab->htable && state->bucket < iterator_get_avtab_size(avtab)); } } while (avtab->htable && state->bucket < iterator_get_avtab_size(avtab) && state->node ? !(state->rule_type_mask & state->node->key.specified) : 0); return STATUS_SUCCESS; } int hash_state_end(const qpol_iterator_t * iter) { hash_state_t *hs = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (hash_state_t *) iter->state; if (hs->table == NULL || *(hs->table) == NULL || (*(hs->table))->nel == 0 || hs->bucket >= (*(hs->table))->size) return 1; return 0; } int ebitmap_state_end(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } es = (ebitmap_state_t *) iter->state; if (es->cur >= es->bmap->highbit) return 1; return 0; } int ocon_state_end(const qpol_iterator_t * iter) { ocon_state_t *os = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } os = (ocon_state_t *) iter->state; if (os->cur == NULL) return 1; return 0; } int avtab_state_end(const qpol_iterator_t * iter) { avtab_state_t *state; avtab_t *avtab; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return STATUS_ERR; } state = iter->state; avtab = (state->which == QPOL_AVTAB_STATE_AV ? state->ucond_tab : state->cond_tab); if ((!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) && state->which == QPOL_AVTAB_STATE_COND) return 1; return 0; } size_t hash_state_size(const qpol_iterator_t * iter) { hash_state_t *hs = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return 0; } hs = (hash_state_t *) iter->state; return (*(hs->table))->nel; } size_t ebitmap_state_size(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; size_t count = 0, bit = 0; ebitmap_node_t *node = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return 0; } es = (ebitmap_state_t *) iter->state; ebitmap_for_each_bit(es->bmap, node, bit) { count += ebitmap_get_bit(es->bmap, bit); } return count; } size_t ocon_state_size(const qpol_iterator_t * iter) { ocon_state_t *os = NULL; size_t count = 0; ocontext_t *ocon = NULL; if (iter == NULL || iter->state == NULL) { errno = EINVAL; return 0; } os = (ocon_state_t *) iter->state; for (ocon = os->head; ocon; ocon = ocon->next) count++; return count; } size_t avtab_state_size(const qpol_iterator_t * iter) { avtab_state_t *state; avtab_t *avtab; size_t count = 0; avtab_ptr_t node = NULL; uint32_t bucket = 0; if (iter == NULL || iter->state == NULL || iter->policy == NULL) { errno = EINVAL; return STATUS_ERR; } state = iter->state; avtab = state->ucond_tab; for (bucket = 0; avtab->htable && bucket < iterator_get_avtab_size(avtab); bucket++) { for (node = avtab->htable[bucket]; node; node = node->next) { if (node->key.specified & state->rule_type_mask) count++; } } avtab = state->cond_tab; for (bucket = 0; avtab->htable && bucket < iterator_get_avtab_size(avtab); bucket++) { for (node = avtab->htable[bucket]; node; node = node->next) { if (node->key.specified & state->rule_type_mask) count++; } } return count; } void qpol_iterator_destroy(qpol_iterator_t ** iter) { if (iter == NULL || *iter == NULL) return; if ((*iter)->free_fn) (*iter)->free_fn((*iter)->state); free(*iter); *iter = NULL; } int qpol_iterator_get_item(const qpol_iterator_t * iter, void **item) { if (item != NULL) *item = NULL; if (iter == NULL || iter->get_cur == NULL || item == NULL) { errno = EINVAL; return STATUS_ERR; } *item = iter->get_cur(iter); if (*item == NULL) return STATUS_ERR; return STATUS_SUCCESS; } int qpol_iterator_next(qpol_iterator_t * iter) { if (iter == NULL || iter->next == NULL) { errno = EINVAL; return STATUS_ERR; } return iter->next(iter); } int qpol_iterator_end(const qpol_iterator_t * iter) { if (iter == NULL || iter->end == NULL) { errno = EINVAL; return STATUS_ERR; } return iter->end(iter); } int qpol_iterator_get_size(const qpol_iterator_t * iter, size_t * size) { if (size != NULL) *size = 0; if (iter == NULL || size == NULL || iter->size == NULL) { errno = EINVAL; return STATUS_ERR; } *size = iter->size(iter); return STATUS_SUCCESS; } void *ebitmap_state_get_cur_type(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; const policydb_t *db = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } es = qpol_iterator_state(iter); if (es == NULL) { errno = EINVAL; return NULL; } db = qpol_iterator_policy(iter); if (db == NULL) { errno = EINVAL; return NULL; } return db->type_val_to_struct[es->cur]; } void *ebitmap_state_get_cur_role(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; const policydb_t *db = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } es = qpol_iterator_state(iter); if (es == NULL) { errno = EINVAL; return NULL; } db = qpol_iterator_policy(iter); if (db == NULL) { errno = EINVAL; return NULL; } return db->role_val_to_struct[es->cur]; } void *ebitmap_state_get_cur_cat(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; const policydb_t *db = NULL; const qpol_cat_t *cat = NULL; sepol_policydb_t sp; qpol_policy_t qp; if (iter == NULL) { errno = EINVAL; return NULL; } es = qpol_iterator_state(iter); if (es == NULL) { errno = EINVAL; return NULL; } db = qpol_iterator_policy(iter); if (db == NULL) { errno = EINVAL; return NULL; } /* shallow copy is safe here */ sp.p = *db; qp.p = &sp; qp.fn = NULL; qpol_policy_get_cat_by_name(&qp, db->p_cat_val_to_name[es->cur], &cat); /* There is no val_to_struct for categories; this requires that qpol * search for the struct, but it can't be returned as const here so * cast it to void* explicitly. */ return (void *)cat; } void *ebitmap_state_get_cur_permissive(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; const policydb_t *db = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } es = qpol_iterator_state(iter); if (es == NULL) { errno = EINVAL; return NULL; } db = qpol_iterator_policy(iter); if (db == NULL) { errno = EINVAL; return NULL; } return db->type_val_to_struct[es->cur - 1]; } void *ebitmap_state_get_cur_polcap(const qpol_iterator_t * iter) { ebitmap_state_t *es = NULL; const policydb_t *db = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } es = qpol_iterator_state(iter); if (es == NULL) { errno = EINVAL; return NULL; } db = qpol_iterator_policy(iter); if (db == NULL) { errno = EINVAL; return NULL; } return (void *)sepol_polcap_getname(es->cur); } void ebitmap_state_destroy(void *es) { ebitmap_state_t *ies = (ebitmap_state_t *) es; if (!es) return; ebitmap_destroy(ies->bmap); free(ies->bmap); free(ies); } int perm_state_end(const qpol_iterator_t * iter) { perm_state_t *ps = NULL; const policydb_t *db = NULL; unsigned int perm_max = 0; if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL) { errno = EINVAL; return STATUS_ERR; } /* permission max is number of permissions in the class which includes * the number of permissions in its common if it inherits one */ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim; if (perm_max > 32) { errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */ return STATUS_ERR; } if (!(ps->perm_set) || ps->cur >= perm_max) return 1; return 0; } void *perm_state_get_cur(const qpol_iterator_t * iter) { const policydb_t *db = NULL; class_datum_t *obj_class = NULL; perm_state_t *ps = NULL; unsigned int perm_max = 0; char *tmp = NULL; if (iter == NULL || (db = qpol_iterator_policy(iter)) == NULL || (ps = (perm_state_t *) qpol_iterator_state(iter)) == NULL || perm_state_end(iter)) { errno = EINVAL; return NULL; } obj_class = db->class_val_to_struct[ps->obj_class_val - 1]; /* permission max is number of permissions in the class which includes * the number of permissions in its common if it inherits one */ perm_max = obj_class->permissions.nprim; if (perm_max > 32) { errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */ return NULL; } if (ps->cur >= perm_max) { errno = ERANGE; return NULL; } if (!(ps->perm_set & 1 << (ps->cur))) { /* perm bit not set? */ errno = EINVAL; return NULL; } /* explicit const_cast for sepol */ tmp = sepol_av_to_string((policydb_t *) db, ps->obj_class_val, (sepol_access_vector_t) 1 << (ps->cur)); if (tmp) { tmp++; /*sepol_av_to_string prepends a ' ' to the name */ return strdup(tmp); } else { errno = EINVAL; return NULL; } } int perm_state_next(qpol_iterator_t * iter) { perm_state_t *ps = NULL; const policydb_t *db = NULL; unsigned int perm_max = 0; if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL || perm_state_end(iter)) { errno = EINVAL; return STATUS_ERR; } /* permission max is number of permissions in the class which includes * the number of permissions in its common if it inherits one */ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim; if (perm_max > 32) { errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */ return STATUS_ERR; } if (ps->cur >= perm_max) { errno = ERANGE; return STATUS_ERR; } do { ps->cur++; } while (ps->cur < perm_max && !(ps->perm_set & 1 << (ps->cur))); return STATUS_SUCCESS; } size_t perm_state_size(const qpol_iterator_t * iter) { perm_state_t *ps = NULL; const policydb_t *db = NULL; unsigned int perm_max = 0; size_t i, count = 0; if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL || perm_state_end(iter)) { errno = EINVAL; return 0; /* as a size_t 0 is error */ } /* permission max is number of permissions in the class which includes * the number of permissions in its common if it inherits one */ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim; if (perm_max > 32) { errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */ return 0; /* as a size_t 0 is error */ } for (i = 0; i < perm_max; i++) { if (ps->perm_set & 1 << i) count++; } return count; } #define XPERMS_DRIV(x) (x >> 8) #define XPERMS_FUNC(x) (x & 0xFF) #define XPERMS_GETBIT(xperms, bit) (xperms[(bit) >> 5] & (1 << ((bit) & 0x1F))) int xperm_state_end(const qpol_iterator_t * iter) { xperm_state_t *xps = NULL; const policydb_t *db = NULL; if (iter == NULL || (xps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL) { errno = EINVAL; return STATUS_ERR; } if (xps->cur > 0xFFFF) return 1; return 0; } void *xperm_state_get_cur(const qpol_iterator_t * iter) { const policydb_t *db = NULL; xperm_state_t *xps = NULL; avtab_extended_perms_t *xperms = NULL; int bitset; int *cur; if (iter == NULL || (db = qpol_iterator_policy(iter)) == NULL || (xps = (xperm_state_t *) qpol_iterator_state(iter)) == NULL || xperm_state_end(iter)) { errno = EINVAL; return NULL; } if (xps->cur > 0xFFFF) { errno = ERANGE; return NULL; } xperms = xps->xperms; if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { bitset = XPERMS_GETBIT(xperms->perms, XPERMS_DRIV(xps->cur)); } else { bitset = (xperms->driver == XPERMS_DRIV(xps->cur)) && XPERMS_GETBIT(xperms->perms, XPERMS_FUNC(xps->cur)); } if (!bitset) { /* xperm bit not set? */ errno = EINVAL; return NULL; } // the caller is responsible for freeing the returned integer. this is // similar to how the caller must also free the resulting string of // perm_state_get_cur cur = calloc(1, sizeof(int)); if (cur == NULL) { return NULL; } *cur = xps->cur; return cur; } int xperm_state_next(qpol_iterator_t * iter) { xperm_state_t *xps = NULL; const policydb_t *db = NULL; avtab_extended_perms_t *xperms = NULL; int bitset = 0; if (iter == NULL || (xps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL || xperm_state_end(iter)) { errno = EINVAL; return STATUS_ERR; } if (xps->cur > 0xFFFF) { errno = ERANGE; return STATUS_ERR; } xperms = xps->xperms; while (1) { xps->cur++; if (xps->cur > 0xFFFF) { break; } if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { bitset = XPERMS_GETBIT(xperms->perms, XPERMS_DRIV(xps->cur)); } else { bitset = (xperms->driver == XPERMS_DRIV(xps->cur)) && XPERMS_GETBIT(xperms->perms, XPERMS_FUNC(xps->cur)); } if (bitset) { break; } } return STATUS_SUCCESS; } size_t xperm_state_size(const qpol_iterator_t * iter) { xperm_state_t *xps = NULL; const policydb_t *db = NULL; avtab_extended_perms_t *xperms = NULL; size_t i, j, count = 0; if (iter == NULL || (xps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL || xperm_state_end(iter)) { errno = EINVAL; return 0; /* as a size_t 0 is error */ } xperms = xps->xperms; // just count how many bits are set in the perms array (size == 8) of uint32_t's for (i = 0; i < 8; i++) { for (j = 0; j < 32; j++) { if (xperms->perms[i] & (1 << j)) { count++; } } } if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { // when icotl driver is true, each bit in the perms array represents // the enabling of all 256 function bits of driver count *= 256; } return count; } setools-4.1.1/libqpol/iterator_internal.h000066400000000000000000000106251314142262400205500ustar00rootroot00000000000000/** * @file * Declaration of the internal interface for * qpol_iterator, an arbitrary valued policy component * iterator used to return lists of components. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_ITERATOR_INTERNAL_H #define QPOL_ITERATOR_INTERNAL_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include typedef struct hash_state { unsigned int bucket; hashtab_node_t *node; hashtab_t *table; } hash_state_t; typedef struct ebitmap_state { ebitmap_t *bmap; size_t cur; } ebitmap_state_t; typedef struct ocon_state { ocontext_t *head; ocontext_t *cur; } ocon_state_t; typedef struct perm_state { uint32_t perm_set; uint32_t obj_class_val; uint8_t cur; } perm_state_t; typedef struct xperm_state { avtab_extended_perms_t *xperms; uint32_t cur; // an extended perm value ranges between 0x0000 and // 0xFFFF. So only 16 bits are necessary to store the // current value, but we want greater than 0xFFFF to represent // reaching the end, so we need a 32 bit int } xperm_state_t; typedef struct avtab_state { uint32_t rule_type_mask; avtab_t *ucond_tab; avtab_t *cond_tab; uint32_t bucket; avtab_ptr_t node; #define QPOL_AVTAB_STATE_AV 0 #define QPOL_AVTAB_STATE_COND 1 unsigned which; } avtab_state_t; int qpol_iterator_create(const qpol_policy_t * policy, void *state, void *(*get_cur) (const qpol_iterator_t * iter), int (*next) (qpol_iterator_t * iter), int (*end) (const qpol_iterator_t * iter), size_t(*size) (const qpol_iterator_t * iter), void (*free_fn) (void *x), qpol_iterator_t ** iter); void *qpol_iterator_state(const qpol_iterator_t * iter); const policydb_t *qpol_iterator_policy(const qpol_iterator_t * iter); void *hash_state_get_cur(const qpol_iterator_t * iter); void *hash_state_get_cur_key(const qpol_iterator_t * iter); void *ebitmap_state_get_cur_type(const qpol_iterator_t * iter); void *ebitmap_state_get_cur_role(const qpol_iterator_t * iter); void *ebitmap_state_get_cur_cat(const qpol_iterator_t * iter); void *ebitmap_state_get_cur_permissive(const qpol_iterator_t * iter); void *ebitmap_state_get_cur_polcap(const qpol_iterator_t * iter); void *ocon_state_get_cur(const qpol_iterator_t * iter); void *perm_state_get_cur(const qpol_iterator_t * iter); void *xperm_state_get_cur(const qpol_iterator_t * iter); void *avtab_state_get_cur(const qpol_iterator_t * iter); int hash_state_next(qpol_iterator_t * iter); int ebitmap_state_next(qpol_iterator_t * iter); int ocon_state_next(qpol_iterator_t * iter); int perm_state_next(qpol_iterator_t * iter); int xperm_state_next(qpol_iterator_t * iter); int avtab_state_next(qpol_iterator_t * iter); int hash_state_end(const qpol_iterator_t * iter); int ebitmap_state_end(const qpol_iterator_t * iter); int ocon_state_end(const qpol_iterator_t * iter); int perm_state_end(const qpol_iterator_t * iter); int xperm_state_end(const qpol_iterator_t * iter); int avtab_state_end(const qpol_iterator_t * iter); size_t hash_state_size(const qpol_iterator_t * iter); size_t ebitmap_state_size(const qpol_iterator_t * iter); size_t ocon_state_size(const qpol_iterator_t * iter); size_t perm_state_size(const qpol_iterator_t * iter); size_t xperm_state_size(const qpol_iterator_t * iter); size_t avtab_state_size(const qpol_iterator_t * iter); void ebitmap_state_destroy(void *es); #ifdef __cplusplus } #endif #endif /* QPOL_ITERATOR_INTERNAL_H */ setools-4.1.1/libqpol/mls_query.c000066400000000000000000000506511314142262400170410ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over * policy MLS components. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007. 2015 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include "iterator_internal.h" #include #include "qpol_internal.h" /* level */ int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum) { policydb_t *db = NULL; hashtab_datum_t internal_datum = NULL; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name); if (internal_datum == NULL) { ERR(policy, "could not find datum for level %s", name); errno = EINVAL; *datum = NULL; return STATUS_ERR; } *datum = (qpol_level_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_levels.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias) { level_datum_t *internal_datum; if (policy == NULL || datum == NULL || isalias == NULL) { if (isalias != NULL) *isalias = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; *isalias = internal_datum->isalias; return STATUS_SUCCESS; } int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value) { level_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; *value = internal_datum->level->sens; return STATUS_SUCCESS; } int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats) { level_datum_t *internal_datum = NULL; ebitmap_state_t *es = NULL; int error = 0; if (policy == NULL || datum == NULL || cats == NULL) { if (cats != NULL) *cats = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_datum->level->cat); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*cats); return STATUS_SUCCESS; } int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name) { level_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (level_datum_t *) datum; *name = db->p_sens_val_to_name[internal_datum->level->sens - 1]; return STATUS_SUCCESS; } typedef struct level_alias_hash_state { unsigned int bucket; hashtab_node_t *node; hashtab_t *table; uint32_t val; } level_alias_hash_state_t; static int hash_state_next_level_alias(qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; level_datum_t *datum = NULL; if (iter == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } do { hash_state_next(iter); datum = hs->node ? (level_datum_t *) hs->node->datum : NULL; } while (datum != NULL && (datum->level->sens != hs->val || !datum->isalias)); return STATUS_SUCCESS; } static void *hash_state_get_cur_alias(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return NULL; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return NULL; } return hs->node->key; } static size_t hash_state_level_alias_size(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; hashtab_node_t *tmp_node; level_datum_t *tmp_lvl_datum; uint32_t tmp_bucket = 0; size_t count = 0; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (!hs) { errno = EINVAL; return STATUS_ERR; } for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { tmp_lvl_datum = tmp_node ? tmp_node->datum : NULL; if (tmp_lvl_datum) { if (tmp_lvl_datum->isalias && tmp_lvl_datum->level->sens == hs->val) count++; } } } return count; } int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases) { level_datum_t *internal_datum = NULL; policydb_t *db = NULL; int error; level_alias_hash_state_t *hs = NULL; if (policy == NULL || datum == NULL || aliases == NULL) { if (aliases != NULL) *aliases = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (level_datum_t *) datum; hs = calloc(1, sizeof(level_alias_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_levels.table; hs->node = (*(hs->table))->htable[0]; hs->val = internal_datum->level->sens; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias, hash_state_next_level_alias, hash_state_end, hash_state_level_alias_size, free, aliases)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || !((level_datum_t *) hs->node->datum)->isalias || ((level_datum_t *) (hs->node->datum))->level->sens != hs->val) hash_state_next_level_alias(*aliases); return STATUS_SUCCESS; } /* cat */ int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)name); if (internal_datum == NULL) { *datum = NULL; ERR(policy, "could not find datum for cat %s", name); errno = EINVAL; return STATUS_ERR; } *datum = (qpol_cat_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_cats.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value) { cat_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cat_datum_t *) datum; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias) { cat_datum_t *internal_datum; if (policy == NULL || datum == NULL || isalias == NULL) { if (isalias != NULL) *isalias = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cat_datum_t *) datum; *isalias = internal_datum->isalias; return STATUS_SUCCESS; } int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name) { cat_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (cat_datum_t *) datum; *name = db->p_cat_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } static int hash_state_next_cat_alias(qpol_iterator_t * iter) { /* using level alias state datum since data needed is identical */ level_alias_hash_state_t *hs = NULL; cat_datum_t *datum = NULL; if (iter == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } do { hash_state_next(iter); datum = hs->node ? (cat_datum_t *) hs->node->datum : NULL; } while (datum != NULL && (datum->s.value != hs->val || !datum->isalias)); return STATUS_SUCCESS; } static size_t hash_state_cat_alias_size(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; hashtab_node_t *tmp_node; cat_datum_t *tmp_cat_datum; uint32_t tmp_bucket = 0; size_t count = 0; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (!hs) { errno = EINVAL; return STATUS_ERR; } for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { tmp_cat_datum = tmp_node ? tmp_node->datum : NULL; if (tmp_cat_datum) { if (tmp_cat_datum->isalias && tmp_cat_datum->s.value == hs->val) count++; } } } return count; } int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases) { cat_datum_t *internal_datum = NULL; policydb_t *db = NULL; int error; level_alias_hash_state_t *hs = NULL; if (policy == NULL || datum == NULL || aliases == NULL) { if (aliases != NULL) *aliases = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (cat_datum_t *) datum; hs = calloc(1, sizeof(level_alias_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_cats.table; hs->node = (*(hs->table))->htable[0]; hs->val = internal_datum->s.value; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias, hash_state_next_cat_alias, hash_state_end, hash_state_cat_alias_size, free, aliases)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || ((cat_datum_t *) (hs->node->datum))->s.value != hs->val) hash_state_next_cat_alias(*aliases); return STATUS_SUCCESS; } /* mls range */ int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t *low, const qpol_mls_level_t *high, qpol_mls_range_t **dest) { mls_range_t *internal_range = NULL; mls_level_t *internal_low = NULL, *internal_high = NULL; if (policy == NULL || low == NULL || high == NULL || dest == NULL) { if (dest != NULL) *dest = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *dest = NULL; internal_low = (mls_level_t*)low; internal_high = (mls_level_t*)high; if (!mls_level_dom(internal_high, internal_low)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = malloc(sizeof(mls_range_t)); if (!internal_range) { ERR(policy, "%s", strerror(errno)); return STATUS_ERR; } mls_range_init(internal_range); if (mls_level_cpy(&internal_range->level[0], internal_low) < 0) { goto err; } if (mls_level_cpy(&internal_range->level[1], internal_high) < 0) { goto err; } *dest = (qpol_mls_range_t*) internal_range; return STATUS_SUCCESS; err: mls_range_destroy(internal_range); free(internal_range); errno = ENOMEM; return STATUS_ERR; } int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level) { mls_range_t *internal_range = NULL; if (policy == NULL || range == NULL || level == NULL) { if (level != NULL) *level = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = (mls_range_t *) range; *level = (qpol_mls_level_t *) & (internal_range->level[0]); return STATUS_SUCCESS; } int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level) { mls_range_t *internal_range = NULL; if (policy == NULL || range == NULL || level == NULL) { if (level != NULL) *level = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = (mls_range_t *) range; *level = (qpol_mls_level_t *) & (internal_range->level[1]); return STATUS_SUCCESS; } /* mls_level */ int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name) { policydb_t *db = NULL; mls_level_t *internal_level = NULL; if (policy == NULL || level == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_level = (mls_level_t *) level; db = &policy->p->p; *name = db->p_sens_val_to_name[internal_level->sens - 1]; return STATUS_SUCCESS; } int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats) { mls_level_t *internal_level = NULL; ebitmap_state_t *es = NULL; int error = 0; if (policy == NULL || level == NULL || cats == NULL) { if (cats != NULL) *cats = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_level = (mls_level_t *) level; es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_level->cat); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*cats); return STATUS_SUCCESS; } int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, const qpol_semantic_level_t * src, qpol_mls_level_t **dest) { policydb_t *db = NULL; mls_semantic_level_t *internal_semantic = NULL; mls_level_t *internal_level = NULL; if (policy == NULL || src == NULL || dest == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; *dest = NULL; return STATUS_ERR; } internal_semantic = (mls_semantic_level_t*) src; db = &policy->p->p; internal_level = malloc(sizeof(mls_level_t)); if (!internal_level) { return STATUS_ERR; } mls_level_init(internal_level); if(mls_semantic_level_expand(internal_semantic, internal_level, db, policy->sh) < 0) { mls_level_destroy(internal_level); free(internal_level); errno = EINVAL; *dest = NULL; return STATUS_ERR; } *dest = (qpol_mls_level_t*) internal_level; return STATUS_SUCCESS; } /* semantic level */ int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_semantic_level_t ** datum) { policydb_t *db = NULL; hashtab_datum_t internal_datum = NULL; mls_semantic_level_t *internal_semantic = NULL; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_semantic = malloc(sizeof(mls_semantic_level_t)); if (!internal_semantic) { return STATUS_ERR; } mls_semantic_level_init(internal_semantic); db = &policy->p->p; internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name); if (internal_datum == NULL) { mls_semantic_level_destroy(internal_semantic); free(internal_semantic); *datum = NULL; ERR(policy, "could not find datum for level %s", name); errno = ENOENT; return STATUS_ERR; } internal_semantic->sens = ((level_datum_t*)internal_datum)->level->sens; *datum = (qpol_semantic_level_t *) internal_semantic; return STATUS_SUCCESS; } int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high) { hashtab_datum_t internal_datum; policydb_t *db = NULL; mls_semantic_level_t *internal_level = NULL; mls_semantic_cat_t *internal_cat = NULL; if (policy == NULL || level == NULL || low == NULL || high == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cat = malloc(sizeof(mls_semantic_cat_t)); if (!internal_cat) { return STATUS_ERR; } mls_semantic_cat_init(internal_cat); db = &policy->p->p; internal_level = (mls_semantic_level_t*) level; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)low); if (internal_datum == NULL) { ERR(policy, "could not find datum for cat %s", low); goto err; } internal_cat->low = ((cat_datum_t*)internal_datum)->s.value; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)high); if (internal_datum == NULL) { ERR(policy, "could not find datum for cat %s", high); goto err; } internal_cat->high = ((cat_datum_t*)internal_datum)->s.value; if (internal_cat->low > internal_cat->high) { ERR(policy, "invalid semantic category range: %s.%s", low, high); goto err; } if (!(internal_level->cat)) { internal_level->cat = internal_cat; } else { mls_semantic_cat_t *curr = internal_level->cat; while(curr->next) { curr = curr->next; } curr->next = internal_cat; } return STATUS_SUCCESS; err: mls_semantic_cat_destroy(internal_cat); free(internal_cat); errno = ENOENT; return STATUS_ERR; } void qpol_semantic_level_destroy(qpol_semantic_level_t * level) { if (level == NULL) { return; } mls_semantic_level_destroy((mls_semantic_level_t*) level); free(level); } setools-4.1.1/libqpol/mlsrule_query.c000066400000000000000000000145441314142262400177320ustar00rootroot00000000000000/** * @file * Implementation for the public interface for searching and iterating over * range transition rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 "iterator_internal.h" #include #include #include #include #include #include #include #include "qpol_internal.h" typedef struct range_trans_state { unsigned int bucket; hashtab_ptr_t cur_item; range_trans_t *cur; } range_trans_state_t; static int range_trans_state_end(const qpol_iterator_t * iter) { range_trans_state_t *rs = NULL; if (!iter || !(rs = qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return rs->cur ? 0 : 1; } static void *range_trans_state_get_cur(const qpol_iterator_t * iter) { range_trans_state_t *rs = NULL; const policydb_t *db = NULL; if (!iter || !(rs = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return NULL; } return rs->cur; } static int range_trans_state_next(qpol_iterator_t * iter) { range_trans_state_t *rs = NULL; const policydb_t *db = NULL; if (!iter || !(rs = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } if (range_trans_state_end(iter)) { errno = EINVAL; return STATUS_ERR; } rs->cur_item = rs->cur_item->next; while (rs->cur_item == NULL) { rs->bucket++; if (rs->bucket >= db->range_tr->size) { break; } rs->cur_item = db->range_tr->htable[rs->bucket]; } if (rs->cur_item == NULL) { rs->cur = NULL; } else { rs->cur = (range_trans_t*)rs->cur_item->key; } return STATUS_SUCCESS; } static size_t range_trans_state_size(const qpol_iterator_t * iter) { range_trans_state_t *rs = NULL; const policydb_t *db = NULL; size_t count = 0; unsigned int i = 0; if (!iter || !(rs = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return 0; } hashtab_ptr_t cur = NULL; for (i = 0; i < db->range_tr->size; i++) { cur = db->range_tr->htable[i]; while (cur != NULL) { count++; cur = cur->next; } } return count; } int qpol_policy_get_range_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; range_trans_state_t *rs = NULL; int error = 0; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rs = calloc(1, sizeof(range_trans_state_t)); if (!rs) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } if (qpol_iterator_create(policy, (void *)rs, range_trans_state_get_cur, range_trans_state_next, range_trans_state_end, range_trans_state_size, free, iter)) { error = errno; free(rs); errno = error; return STATUS_ERR; } rs->bucket = 0; rs->cur_item = db->range_tr->htable[0]; rs->cur = NULL; rs->cur_item = db->range_tr->htable[rs->bucket]; while (rs->cur_item == NULL) { rs->bucket++; if (rs->bucket >= db->range_tr->size) { break; } rs->cur_item = db->range_tr->htable[rs->bucket]; } if (rs->cur_item != NULL) { rs->cur = (range_trans_t*)rs->cur_item->key; } return STATUS_SUCCESS; } int qpol_range_trans_get_source_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** source) { policydb_t *db = NULL; range_trans_t *rt = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { errno = EINVAL; ERR(policy, "%s", strerror(EINVAL)); return STATUS_ERR; } db = &policy->p->p; rt = (range_trans_t *) rule; *source = (qpol_type_t *) db->type_val_to_struct[rt->source_type - 1]; return STATUS_SUCCESS; } int qpol_range_trans_get_target_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** target) { policydb_t *db = NULL; range_trans_t *rt = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (range_trans_t *) rule; *target = (qpol_type_t *) db->type_val_to_struct[rt->target_type - 1]; return STATUS_SUCCESS; } int qpol_range_trans_get_target_class(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_class_t ** target) { policydb_t *db = NULL; range_trans_t *rt = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (range_trans_t *) rule; *target = (qpol_class_t *) db->class_val_to_struct[rt->target_class - 1]; return STATUS_SUCCESS; } int qpol_range_trans_get_range(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_mls_range_t ** range) { range_trans_t *rt = NULL; if (range) { *range = NULL; } if (!policy || !rule || !range) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } policydb_t *db = &policy->p->p; rt = (range_trans_t *) rule; mls_range_t *target_range = NULL; target_range = hashtab_search(db->range_tr, (hashtab_key_t)rt); if (target_range == NULL) { return STATUS_ERR; } *range = (qpol_mls_range_t *)target_range; return STATUS_SUCCESS; } setools-4.1.1/libqpol/module.c000066400000000000000000000105261314142262400163030ustar00rootroot00000000000000/** * @file * Defines the public interface the QPol policy. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * @author Brandon Whalen bwhalen@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include "qpol_internal.h" #include #include int qpol_module_create_from_file(const char *path, qpol_module_t ** module) { sepol_module_package_t *smp = NULL; sepol_policy_file_t *spf = NULL; FILE *infile = NULL; int error = 0; char *tmp = NULL; char *data = NULL; if (module) *module = NULL; if (!path || !module) { errno = EINVAL; return STATUS_ERR; } if (!(*module = calloc(1, sizeof(qpol_module_t)))) { return STATUS_ERR; } if (!((*module)->path = strdup(path))) { error = errno; goto err; } if (sepol_policy_file_create(&spf)) { error = errno; goto err; } infile = fopen(path, "rb"); if (!infile) { error = errno; goto err; } if (!qpol_is_file_mod_pkg(infile)) { error = ENOTSUP; goto err; } rewind(infile); sepol_policy_file_set_fp(spf, infile); if (sepol_module_package_create(&smp)) { error = EIO; goto err; } if (sepol_module_package_info(spf, &((*module)->type), &((*module)->name), &tmp)) { error = EIO; goto err; } free(tmp); tmp = NULL; rewind(infile); if (sepol_module_package_read(smp, spf, 0)) { error = EIO; goto err; } if (!((*module)->p = sepol_module_package_get_policy(smp))) { error = EIO; goto err; } /* set the module package's policy to NULL as the qpol module owns it now */ smp->policy = NULL; (*module)->version = (*module)->p->p.version; (*module)->enabled = 1; sepol_module_package_free(smp); fclose(infile); if (data != NULL) free (data); sepol_policy_file_free(spf); return STATUS_SUCCESS; err: qpol_module_destroy(module); sepol_policy_file_free(spf); sepol_module_package_free(smp); if (infile) fclose(infile); if (data != NULL) free (data); if (tmp != NULL) free(tmp); errno = error; return STATUS_ERR; } void qpol_module_destroy(qpol_module_t ** module) { if (!module || !(*module)) return; free((*module)->path); free((*module)->name); sepol_policydb_free((*module)->p); free(*module); *module = NULL; } int qpol_module_get_path(const qpol_module_t * module, const char **path) { if (!module || !path) { errno = EINVAL; return STATUS_ERR; } *path = module->path; return STATUS_SUCCESS; } int qpol_module_get_name(const qpol_module_t * module, const char **name) { if (!module || !name) { errno = EINVAL; return STATUS_ERR; } *name = module->name; return STATUS_SUCCESS; } int qpol_module_get_version(const qpol_module_t * module, const char **version) { if (!module || !version) { errno = EINVAL; return STATUS_ERR; } *version = module->version; return STATUS_SUCCESS; } int qpol_module_get_type(const qpol_module_t * module, int *type) { if (!module || !type) { errno = EINVAL; return STATUS_ERR; } *type = module->type; return STATUS_SUCCESS; } int qpol_module_get_enabled(const qpol_module_t * module, int *enabled) { if (!module || !enabled) { errno = EINVAL; return STATUS_ERR; } *enabled = module->enabled; return STATUS_SUCCESS; } int qpol_module_set_enabled(qpol_module_t * module, int enabled) { if (!module) { errno = EINVAL; return STATUS_ERR; } if (enabled != module->enabled && module->parent) { module->parent->modified = 1; } module->enabled = enabled; return STATUS_SUCCESS; } setools-4.1.1/libqpol/module_compiler.c000066400000000000000000001135561314142262400202040ustar00rootroot00000000000000/* This file is a copy of module_compiler.c from checkpolicy 2.4 to support * SETools. */ /* Author : Joshua Brindle * Karl MacMillan * Jason Tang * 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. */ /* Required for SETools libqpol services */ #include #include #include #include #include #include #include #include #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(const char *msg); __attribute__ ((format(printf, 1, 2))) extern void yyerror2(const 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 *)(void *)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:{ abort(); /* 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:{ abort(); /* 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:{ abort(); /* 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 *)(void *)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) { uint32_t 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:{ abort(); /* 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:{ abort(); /* 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:{ abort(); /* 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:{ abort(); /* should never get here */ } } } static int require_bool_tunable(int pass, int is_tunable) { 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; } if (is_tunable) booldatum->flags |= COND_BOOL_FLAGS_TUNABLE; retval = require_symbol(SYM_BOOLS, id, (hashtab_datum_t *) (void *) 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:{ abort(); /* should never get here */ } } } int require_bool(int pass) { return require_bool_tunable(pass, 0); } int require_tunable(int pass) { return require_bool_tunable(pass, 1); } 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:{ abort(); /* 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 *) (void *)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:{ abort(); /* should never get here */ } } } static int is_scope_in_stack(scope_datum_t * scope, scope_stack_t * stack) { uint32_t 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; } old_cond->flags |= cond->flags; } 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 __attribute__ ((unused))) { /* 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) { uint32_t 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; } setools-4.1.1/libqpol/module_compiler.h000066400000000000000000000112111314142262400201720ustar00rootroot00000000000000/* This file is a copy of module_compiler.h from checkpolicy 2.4 to support * SETools. */ /* Author : Joshua Brindle * Karl MacMillan * Jason Tang * 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 /* Required for SETools libqpol services */ #ifdef __cplusplus extern "C" { #endif #include /* 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_tunable(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); /* Required for SETools libqpol services */ #ifdef __cplusplus } #endif #endif setools-4.1.1/libqpol/netifcon_query.c000066400000000000000000000077271314142262400200610ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over netifcon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_policy_get_netifcon_by_name(const qpol_policy_t * policy, const char *name, const qpol_netifcon_t ** ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || name == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_NETIF]; tmp; tmp = tmp->next) { if (!strcmp(name, tmp->u.name)) break; } *ocon = (qpol_netifcon_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find netifcon statement for %s", name); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_netifcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_NETIF]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_netifcon_get_name(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const char **name) { ocontext_t *internal_ocon = NULL; if (name != NULL) *name = NULL; if (policy == NULL || ocon == NULL || name == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *name = internal_ocon->u.name; return STATUS_SUCCESS; } int qpol_netifcon_get_msg_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) & (internal_ocon->context[1]); return STATUS_SUCCESS; } int qpol_netifcon_get_if_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) & (internal_ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/libqpol/nodecon_query.c000066400000000000000000000167311314142262400176740ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over nodecon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" struct qpol_nodecon { ocontext_t *ocon; unsigned char protocol; }; int qpol_policy_get_nodecon_by_node(const qpol_policy_t * policy, uint32_t addr[4], uint32_t mask[4], unsigned char protocol, qpol_nodecon_t ** ocon) { policydb_t *db = NULL; ocontext_t *tmp = NULL; int error = 0; if (ocon != NULL) *ocon = NULL; if (policy == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[(protocol == QPOL_IPV4 ? OCON_NODE : OCON_NODE6)]; tmp; tmp = tmp->next) { if (protocol == QPOL_IPV4) { if (addr[0] != tmp->u.node.addr || mask[0] != tmp->u.node.mask) continue; } else { if (memcmp(addr, tmp->u.node6.addr, 16) || memcmp(mask, tmp->u.node6.mask, 16)) continue; } *ocon = calloc(1, sizeof(qpol_nodecon_t)); if (*ocon == NULL) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } (*ocon)->protocol = protocol == QPOL_IPV4 ? QPOL_IPV4 : QPOL_IPV6; (*ocon)->ocon = tmp; } if (*ocon == NULL) { ERR(policy, "%s", "could not find nodecon statement for node"); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } typedef struct node_state { ocon_state_t *v4state; ocon_state_t *v6state; } node_state_t; static void node_state_free(void *ns) { node_state_t *ins = (node_state_t *) ns; if (!ns) return; free(ins->v4state); free(ins->v6state); free(ns); } static int node_state_end(const qpol_iterator_t * iter) { node_state_t *ns = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } ns = (node_state_t *) qpol_iterator_state(iter); return (ns->v4state->cur == NULL && ns->v6state->cur == NULL); } static void *node_state_get_cur(const qpol_iterator_t * iter) { node_state_t *ns = NULL; qpol_nodecon_t *node = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL || node_state_end(iter)) { errno = EINVAL; return NULL; } ns = (node_state_t *) qpol_iterator_state(iter); node = calloc(1, sizeof(qpol_nodecon_t)); if (!node) { return NULL; } node->ocon = ns->v4state->cur ? ns->v4state->cur : ns->v6state->cur; node->protocol = ns->v4state->cur ? QPOL_IPV4 : QPOL_IPV6; return node; } static size_t node_state_size(const qpol_iterator_t * iter) { node_state_t *ns = NULL; size_t count = 0; ocontext_t *ocon = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } ns = (node_state_t *) qpol_iterator_state(iter); if (ns->v4state) for (ocon = ns->v4state->head; ocon; ocon = ocon->next) count++; if (ns->v6state) for (ocon = ns->v6state->head; ocon; ocon = ocon->next) count++; return count; } static int node_state_next(qpol_iterator_t * iter) { node_state_t *ns = NULL; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return STATUS_ERR; } ns = (node_state_t *) qpol_iterator_state(iter); if (ns->v4state->cur == NULL && ns->v6state->cur == NULL) { errno = ERANGE; return STATUS_ERR; } if (ns->v4state->cur) ns->v4state->cur = ns->v4state->cur->next; else ns->v6state->cur = ns->v6state->cur->next; return STATUS_SUCCESS; } int qpol_policy_get_nodecon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *v4os = NULL, *v6os = NULL; node_state_t *ns = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; v4os = calloc(1, sizeof(ocon_state_t)); if (v4os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } v4os->head = v4os->cur = db->ocontexts[OCON_NODE]; v6os = calloc(1, sizeof(ocon_state_t)); if (v6os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); free(v4os); errno = error; return STATUS_ERR; } v6os->head = v6os->cur = db->ocontexts[OCON_NODE6]; ns = calloc(1, sizeof(node_state_t)); if (ns == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); free(v4os); free(v6os); errno = error; return STATUS_ERR; } ns->v4state = v4os; ns->v6state = v6os; if (qpol_iterator_create(policy, (void *)ns, node_state_get_cur, node_state_next, node_state_end, node_state_size, node_state_free, iter)) { node_state_free(ns); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_nodecon_get_addr(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** addr, unsigned char *protocol) { if (addr != NULL) *addr = NULL; if (protocol != NULL) *protocol = 0; if (policy == NULL || ocon == NULL || addr == NULL || protocol == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *protocol = ocon->protocol; if (ocon->protocol == QPOL_IPV4) { *addr = &(ocon->ocon->u.node.addr); } else { *addr = ocon->ocon->u.node6.addr; } return STATUS_SUCCESS; } int qpol_nodecon_get_mask(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** mask, unsigned char *protocol) { if (mask != NULL) *mask = NULL; if (protocol != NULL) *protocol = 0; if (policy == NULL || ocon == NULL || mask == NULL || protocol == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *protocol = ocon->protocol; if (ocon->protocol == QPOL_IPV4) { *mask = &(ocon->ocon->u.node.mask); } else { *mask = ocon->ocon->u.node6.mask; } return STATUS_SUCCESS; } int qpol_nodecon_get_protocol(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, unsigned char *protocol) { if (protocol != NULL) *protocol = 0; if (policy == NULL || ocon == NULL || protocol == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *protocol = ocon->protocol; return STATUS_SUCCESS; } int qpol_nodecon_get_context(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, const qpol_context_t ** context) { if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *context = (qpol_context_t *) & (ocon->ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/libqpol/permissive_query.c000066400000000000000000000050671314142262400204350ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the permissive types. * * @author Steve Lawrence slawrence@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_permissive_get_name(const qpol_policy_t *policy, const qpol_permissive_t * datum, const char **name) { type_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (type_datum_t *)datum; *name = db->p_type_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } int qpol_policy_get_permissive_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { int error = 0; policydb_t *db; ebitmap_state_t *state = NULL; if (iter) { *iter = NULL; } if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; state = calloc(1, sizeof(ebitmap_state_t)); if (state == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } state->bmap = &(db->permissive_map); state->cur = state->bmap->node ? state->bmap->node->startbit : 0; if (qpol_iterator_create(policy, state, ebitmap_state_get_cur_permissive, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) { free(state); return STATUS_ERR; } if (state->bmap->node && !ebitmap_get_bit(state->bmap, state->cur)) ebitmap_state_next(*iter); return STATUS_SUCCESS; } setools-4.1.1/libqpol/polcap_query.c000066400000000000000000000047011314142262400175170ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over the policy capabilities. * * @author Steve Lawrence slawrence@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_polcap_get_name(const qpol_policy_t *policy, const qpol_polcap_t * datum, const char **name) { char *internal_datum = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (char *) datum; *name = internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_polcap_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { int error = 0; policydb_t *db; ebitmap_state_t *state = NULL; if (iter) { *iter = NULL; } if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; state = calloc(1, sizeof(ebitmap_state_t)); if (state == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } state->bmap = &(db->policycaps); state->cur = state->bmap->node ? state->bmap->node->startbit : 0; if (qpol_iterator_create(policy, state, ebitmap_state_get_cur_polcap, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) { free(state); return STATUS_ERR; } if (state->bmap->node && !ebitmap_get_bit(state->bmap, state->cur)) ebitmap_state_next(*iter); return STATUS_SUCCESS; } setools-4.1.1/libqpol/policy.c000066400000000000000000001060511314142262400163140ustar00rootroot00000000000000/** * @file * Defines the public interface the QPol policy. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * @author Brandon Whalen bwhalen@tresys.com * @author Jeremy Solt jsolt@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "qpol_internal.h" #include #include #include #include #include #include #include #include #ifdef DARWIN # include # include # include #else # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "expand.h" #include "queue.h" #include "iterator_internal.h" /* redefine input so we can read from a string */ /* borrowed from O'Reilly lex and yacc pg 157 */ char *qpol_src_originalinput; char *qpol_src_input; char *qpol_src_inputptr; /* current position in qpol_src_input */ char *qpol_src_inputlim; /* end of data */ extern void init_scanner(void); extern int yyparse(void); extern void init_parser(int, int); extern queue_t id_queue; extern unsigned int policydb_errors; extern unsigned long policydb_lineno; extern char source_file[]; extern policydb_t *policydbp; extern int mlspol; extern int xenpol; #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_le16(x) (x) #define le16_to_cpu(x) (x) #define cpu_to_le32(x) (x) #define le32_to_cpu(x) (x) #define cpu_to_le64(x) (x) #define le64_to_cpu(x) (x) #else #define cpu_to_le16(x) bswap_16(x) #define le16_to_cpu(x) bswap_16(x) #define cpu_to_le32(x) bswap_32(x) #define le32_to_cpu(x) bswap_32(x) #define cpu_to_le64(x) bswap_64(x) #define le64_to_cpu(x) bswap_64(x) #endif /* buffer for reading from file */ typedef struct fbuf { char *buf; size_t sz; int err; } qpol_fbuf_t; __attribute__ ((format(printf, 4, 0))) static void qpol_handle_route_to_callback(void *varg __attribute__ ((unused)), const qpol_policy_t * p, int level, const char *fmt, va_list va_args) { if (!p || !(p->fn)) { vfprintf(stderr, fmt, va_args); fprintf(stderr, "\n"); return; } p->fn(p->varg, p, level, fmt, va_args); } __attribute__ ((format(printf, 3, 4))) static void sepol_handle_route_to_callback(void *varg, sepol_handle_t * sh, const char *fmt, ...) { va_list ap; qpol_policy_t *p = varg; if (!sh) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); return; } va_start(ap, fmt); qpol_handle_route_to_callback(NULL, p, sepol_msg_get_level(sh), fmt, ap); va_end(ap); } __attribute__ ((format(printf, 3, 4))) void qpol_handle_msg(const qpol_policy_t * p, int level, const char *fmt, ...) { va_list ap; if (!p) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); return; } va_start(ap, fmt); /* explicit cast here to remove const for sepol handle */ qpol_handle_route_to_callback((void *)p->varg, p, level, fmt, ap); va_end(ap); } __attribute__ ((format(printf, 4, 0))) static void qpol_handle_default_callback(void *varg __attribute__ ((unused)), const qpol_policy_t * p __attribute__ ((unused)), int level, const char *fmt, va_list va_args) { switch (level) { case QPOL_MSG_INFO: { /* by default ignore info messages */ return; } case QPOL_MSG_WARN: { fprintf(stderr, "WARNING: "); break; } case QPOL_MSG_ERR: default: { fprintf(stderr, "ERROR: "); break; } } vfprintf(stderr, fmt, va_args); fprintf(stderr, "\n"); } static int read_source_policy(qpol_policy_t * qpolicy, const char *progname, int options) { int load_rules = 1; if (options & QPOL_POLICY_OPTION_NO_RULES) load_rules = 0; if ((id_queue = queue_create()) == NULL) { ERR(qpolicy, "%s", strerror(ENOMEM)); return -1; } policydbp = &qpolicy->p->p; mlspol = policydbp->mls; xenpol = policydbp->target_platform; INFO(qpolicy, "%s", "Parsing policy. (Step 1 of 5)"); init_scanner(); init_parser(1, load_rules); errno = 0; if (yyparse() || policydb_errors) { ERR(qpolicy, "%s: error(s) encountered while parsing configuration\n", progname); queue_destroy(id_queue); id_queue = NULL; errno = EINVAL; return -1; } /* rewind the pointer */ qpol_src_inputptr = qpol_src_originalinput; init_parser(2, load_rules); source_file[0] = '\0'; if (yyparse() || policydb_errors) { ERR(qpolicy, "%s: error(s) encountered while parsing configuration\n", progname); queue_destroy(id_queue); id_queue = NULL; errno = EINVAL; return -1; } queue_destroy(id_queue); id_queue = NULL; if (policydb_errors) { errno = EINVAL; return -1; } return 0; } static int qpol_init_fbuf(qpol_fbuf_t ** fb) { if (fb == NULL) return -1; *fb = (qpol_fbuf_t *) malloc(sizeof(qpol_fbuf_t)); if (*fb == NULL) return -1; (*fb)->buf = NULL; (*fb)->sz = 0; (*fb)->err = 0; return 0; } static void qpol_free_fbuf(qpol_fbuf_t ** fb) { if (*fb == NULL) return; if ((*fb)->sz > 0 && (*fb)->buf != NULL) free((*fb)->buf); free(*fb); return; } static void *qpol_read_fbuf(qpol_fbuf_t * fb, size_t bytes, FILE * fp) { size_t sz; assert(fb != NULL && fp != NULL); assert(!(fb->sz > 0 && fb->buf == NULL)); if (fb->sz == 0) { fb->buf = (char *)malloc(bytes + 1); fb->sz = bytes + 1; } else if (bytes + 1 > fb->sz) { fb->buf = (char *)realloc(fb->buf, bytes + 1); fb->sz = bytes + 1; } if (fb->buf == NULL) { fb->err = -1; return NULL; } sz = fread(fb->buf, bytes, 1, fp); if (sz != 1) { fb->err = -3; return NULL; } fb->err = 0; return fb->buf; } int qpol_binpol_version(FILE * fp) { __u32 *buf; int rt, len; qpol_fbuf_t *fb; if (fp == NULL) return -1; if (qpol_init_fbuf(&fb) != 0) return -1; /* magic # and sz of policy string */ buf = qpol_read_fbuf(fb, sizeof(__u32) * 2, fp); if (buf == NULL) { rt = fb->err; goto err_return; } buf[0] = le32_to_cpu(buf[0]); if (buf[0] != SELINUX_MAGIC) { rt = -2; goto err_return; } len = le32_to_cpu(buf[1]); if (len < 0) { rt = -3; goto err_return; } /* skip over the policy string */ if (fseek(fp, sizeof(char) * len, SEEK_CUR) != 0) { rt = -3; goto err_return; } /* Read the version, config, and table sizes. */ buf = qpol_read_fbuf(fb, sizeof(__u32) * 1, fp); if (buf == NULL) { rt = fb->err; goto err_return; } buf[0] = le32_to_cpu(buf[0]); rt = buf[0]; err_return: rewind(fp); qpol_free_fbuf(&fb); return rt; } int qpol_is_file_binpol(FILE * fp) { int rt; size_t sz; __u32 ubuf; sz = fread(&ubuf, sizeof(__u32), 1, fp); if (sz != 1) rt = 0; ubuf = le32_to_cpu(ubuf); if (ubuf == SELINUX_MAGIC) rt = 1; else rt = 0; rewind(fp); return rt; } int qpol_is_data_mod_pkg(char * data) { __u32 ubuf; memcpy(&ubuf, data, sizeof(__u32)); ubuf = le32_to_cpu(ubuf); if (ubuf == SEPOL_MODULE_PACKAGE_MAGIC) return 1; return 0; } int qpol_is_file_mod_pkg(FILE * fp) { size_t sz; __u32 ubuf; int rt; sz = fread(&ubuf, sizeof(__u32), 1, fp); if (sz != 1) rt = 0; /* problem reading file */ ubuf = le32_to_cpu(ubuf); if (ubuf == SEPOL_MODULE_PACKAGE_MAGIC) rt = 1; else rt = 0; rewind(fp); return rt; } static int infer_policy_version(qpol_policy_t * policy) { policydb_t *db = NULL; if (!policy) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; if (db->policyvers) { /* version already set */ return STATUS_SUCCESS; } /* Do not try to infer policy version, as it is * a compile-time setting, and the policy can * be downgraded. */ db->policyvers = POLICYDB_VERSION_MAX; return STATUS_SUCCESS; } /** State tracking struct used in the functions check_disabled, remove_symbol, and prune_disabled_symbols to handle disabled symbols */ struct symbol_pruning_state { qpol_policy_t *p; /**< The policy */ int symbol_type; /**< The current symbol type being processed */ }; /** Apply callback for hashtab_map_remove_on_error. * This function tests whether a symbol referenced by the policy is declared or only ever required. * Symbols without a declaration are disabled and must be removed. * @param key Symbol key to check. * @param datum Symbol datum to check. * @param args State object (of type struct symbol_pruning_state) * @return 0 if symbol is enabled, 1 if not enabled. */ static int check_disabled(hashtab_key_t key, hashtab_datum_t datum, void *args) { struct symbol_pruning_state *s = args; if (!is_id_enabled((char *)key, &(s->p->p->p), s->symbol_type)) return 1; return 0; } /** Remove callback for hashtab_map_remove_on_error. * Frees all memory associated with a disabled symbol that has been removed from the symbol table. * @param key Symbol key to remove * @param datum Symbol datum to remove * @param args State object (of type struct symbol_pruning_state) * @post All memory associated with the symbol is freed. */ static void remove_symbol(hashtab_key_t key, hashtab_datum_t datum, void *args) { struct symbol_pruning_state *s = args; switch (s->symbol_type) { case SYM_ROLES: { role_datum_destroy((role_datum_t *) datum); break; } case SYM_TYPES: { type_datum_destroy((type_datum_t *) datum); break; } case SYM_USERS: { user_datum_destroy((user_datum_t *) datum); break; } case SYM_BOOLS: { /* no-op */ break; } case SYM_LEVELS: { level_datum_destroy((level_datum_t *) datum); break; } case SYM_CATS: { cat_datum_destroy((cat_datum_t *) datum); break; } default: return; /* invalid type of datum to free; do nothing */ } free(key); free(datum); } /** Remove symbols that are only required but never declared from the policy. * Removes each disabled symbol freeing all memory associated with it. * @param policy The policy from which disabled symbols should be removed. * @return always 0. * @note Since hashtab_map_remove_on_error does not return any error status, * it is impossible to tell if it has failed; if it fails, the policy will * be in an inconsistent state. */ static int prune_disabled_symbols(qpol_policy_t * policy) { if (policy->type == QPOL_POLICY_KERNEL_BINARY) return 0; /* checkpolicy already prunes disabled symbols */ struct symbol_pruning_state state; state.p = policy; for (state.symbol_type = SYM_ROLES; state.symbol_type < SYM_NUM; state.symbol_type++) { hashtab_map_remove_on_error(policy->p->p.symtab[state.symbol_type].table, check_disabled, remove_symbol, &state); } return 0; } /** For all symbols that are multiply defined (such as attributes, roles, and users), * union the relevant sets of types and roles from each declaration. * @param policy The policy containig the symbols to union. * @return 0 on success, non-zero on error; if the call fails, * errno will be set, and the policy should be considered invalid. */ static int union_multiply_declared_symbols(qpol_policy_t * policy) { /* general structure of this function: walk role and user symbol tables for each role/user/attribute get datum from symtab, get key from array look up symbol in scope table foreach decl_id in scope entry union types/roles bitmap with datum's copy */ qpol_iterator_t * iter = NULL; int error = 0; if (qpol_policy_get_type_iter(policy, &iter)) { return 1; } for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { type_datum_t *attr; if (qpol_iterator_get_item(iter, (void**)&attr)) { error = errno; goto err; } unsigned char isattr = 0; if (qpol_type_get_isattr(policy, (qpol_type_t*)attr, &isattr)) { error = errno; goto err; } if (!isattr) continue; const char *name; if (qpol_type_get_name(policy, (qpol_type_t*)attr, &name)) { error = errno; goto err; } policydb_t *db = &policy->p->p; avrule_block_t *blk = db->global; for (; blk; blk = blk->next) { avrule_decl_t *decl = blk->enabled; if (!decl) continue; /* disabled */ type_datum_t *internal_datum = hashtab_search(decl->symtab[SYM_TYPES].table, (hashtab_key_t)name); if (internal_datum == NULL) { continue; /* not declared here */ } if (ebitmap_union(&attr->types, &internal_datum->types)) { error = errno; ERR(policy, "could not merge declarations for attribute %s", name); goto err; } } } qpol_iterator_destroy(&iter); /* repeat for roles */ if (qpol_policy_get_role_iter(policy, &iter)) { return 1; } for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { role_datum_t *role; uint32_t i; if (qpol_iterator_get_item(iter, (void**)&role)) { error = errno; goto err; } const char *name; if (qpol_role_get_name(policy, (qpol_role_t*)role, &name)) { error = errno; goto err; } policydb_t *db = &policy->p->p; scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_ROLES].table, (hashtab_key_t)name); if (scope_datum == NULL) { ERR(policy, "could not find scope datum for role %s", name); error = ENOENT; goto err; } for (i = 0; i < scope_datum->decl_ids_len; i++) { if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0) continue; /* block is disabled */ role_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->symtab[SYM_ROLES].table, (hashtab_key_t)name); if (internal_datum == NULL) { continue; /* not declared here */ } if (ebitmap_union(&role->types.types, &internal_datum->types.types) || ebitmap_union(&role->dominates, &internal_datum->dominates)) { error = errno; ERR(policy, "could not merge declarations for role %s", name); goto err; } } } qpol_iterator_destroy(&iter); /* repeat for users */ if (qpol_policy_get_user_iter(policy, &iter)) { return 1; } for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { user_datum_t *user; uint32_t i; if (qpol_iterator_get_item(iter, (void**)&user)) { error = errno; goto err; } const char *name; if (qpol_user_get_name(policy, (qpol_user_t*)user, &name)) { error = errno; goto err; } policydb_t *db = &policy->p->p; scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_USERS].table, (hashtab_key_t)name); if (scope_datum == NULL) { ERR(policy, "could not find scope datum for user %s", name); error = ENOENT; goto err; } for (i = 0; i < scope_datum->decl_ids_len; i++) { if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0) continue; /* block is disabled */ user_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] -1 ]->symtab[SYM_USERS].table, (hashtab_key_t)name); if (internal_datum == NULL) { continue; /* not declared here */ } if (ebitmap_union(&user->roles.roles, &internal_datum->roles.roles)) { error = errno; ERR(policy, "could not merge declarations for user %s", name); goto err; } } } qpol_iterator_destroy(&iter); return 0; err: qpol_iterator_destroy(&iter); errno = error; return 1; } /** * @brief Internal version of qpol_policy_rebuild() version 1.3 * * Implementation of the exported function qpol_policy_rebuild() * for version 1.3; this symbol name is not exported. * @see qpol_policy_rebuild() */ int qpol_policy_rebuild(qpol_policy_t * policy, const int options) { sepol_policydb_t *old_p = NULL; sepol_policydb_t **modules = NULL; qpol_module_t *base = NULL; size_t num_modules = 0, i; int error = 0, old_options; if (!policy) { ERR(NULL, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } /* if kernel binary do nothing */ if (policy->type == QPOL_POLICY_KERNEL_BINARY) return STATUS_SUCCESS; /* if options are the same and the modules were not modified, do nothing */ if (options == policy->options && policy->modified == 0) return STATUS_SUCCESS; /* cache old policy in case of failure */ old_p = policy->p; policy->p = NULL; old_options = policy->options; policy->options = options; /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */ if (policy->options & QPOL_POLICY_OPTION_NO_RULES) policy->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS; if (policy->type == QPOL_POLICY_MODULE_BINARY) { /* allocate enough space for all modules then fill with list of enabled ones only */ if (!(modules = calloc(policy->num_modules, sizeof(sepol_policydb_t *)))) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } /* first module is base and cannot be disabled */ for (i = 1; i < policy->num_modules; i++) { if ((policy->modules[i])->enabled) { modules[num_modules++] = (policy->modules[i])->p; } } /* have to reopen the base since link alters it */ if (qpol_module_create_from_file((policy->modules[0])->path, &base)) { error = errno; ERR(policy, "%s", strerror(error)); goto err; } /* take the policy from base and use as new base into which to link */ policy->p = base->p; base->p = NULL; qpol_module_destroy(&base); if (sepol_link_modules(policy->sh, policy->p, modules, num_modules, 0)) { error = EIO; goto err; } free(modules); } else { /* repeat open process as if qpol_policy_open_from_memory() */ if (sepol_policydb_create(&(policy->p))) { error = errno; goto err; } qpol_src_input = policy->file_data; qpol_src_inputptr = qpol_src_input; qpol_src_inputlim = qpol_src_inputptr + policy->file_data_sz - 1; qpol_src_originalinput = qpol_src_input; /* read in source */ policy->p->p.policy_type = POLICY_BASE; if (read_source_policy(policy, "parse", policy->options) < 0) { error = errno; goto err; } /* link the source */ INFO(policy, "%s", "Linking source policy. (Step 2 of 5)"); if (sepol_link_modules(policy->sh, policy->p, NULL, 0, 0)) { error = EIO; goto err; } avtab_destroy(&(policy->p->p.te_avtab)); avtab_destroy(&(policy->p->p.te_cond_avtab)); avtab_init(&(policy->p->p.te_avtab)); avtab_init(&(policy->p->p.te_cond_avtab)); } if (prune_disabled_symbols(policy)) { error = errno; goto err; } if (union_multiply_declared_symbols(policy)) { error = errno; goto err; } if (qpol_expand_module(policy, !(policy->options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) { error = errno; goto err; } if (infer_policy_version(policy)) { error = errno; goto err; } if (policy_extend(policy)) { error = errno; goto err; } sepol_policydb_free(old_p); return STATUS_SUCCESS; err: free(modules); policy->p = old_p; policy->options = old_options; errno = error; return STATUS_ERR; } /** * @brief Internal version of qpol_policy_open_from_file() version 1.3 * * Implementation of the exported function qpol_policy_open_from_file() * for version 1.3; this symbol name is not exported. * @see qpol_policy_open_from_file() */ int qpol_policy_open_from_file(const char *path, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg, const int options) { int error = 0, retv = -1; FILE *infile = NULL; sepol_policy_file_t *pfile = NULL; qpol_module_t *mod = NULL; int fd = 0; struct stat sb; if (policy != NULL) *policy = NULL; if (path == NULL || policy == NULL) { /* handle passed as NULL here as it has yet to be created */ ERR(NULL, "%s", strerror(EINVAL)); errno = EINVAL; return -1; } errno = 0; if (!(*policy = calloc(1, sizeof(qpol_policy_t)))) { error = errno; ERR(NULL, "%s", strerror(error)); goto err; } (*policy)->options = options; /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */ if ((*policy)->options & QPOL_POLICY_OPTION_NO_RULES) (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS; (*policy)->sh = sepol_handle_create(); if ((*policy)->sh == NULL) { error = errno; ERR(*policy, "%s", strerror(error)); errno = error; return -1; } if (fn) { (*policy)->fn = fn; (*policy)->varg = varg; } else { (*policy)->fn = qpol_handle_default_callback; } sepol_msg_set_callback((*policy)->sh, sepol_handle_route_to_callback, (*policy)); if (sepol_policydb_create(&((*policy)->p))) { error = errno; goto err; } if (sepol_policy_file_create(&pfile)) { error = errno; goto err; } infile = fopen(path, "rb"); if (infile == NULL) { error = errno; goto err; } sepol_policy_file_set_handle(pfile, (*policy)->sh); errno=0; if (qpol_is_file_binpol(infile)) { (*policy)->type = retv = QPOL_POLICY_KERNEL_BINARY; sepol_policy_file_set_fp(pfile, infile); if (sepol_policydb_read((*policy)->p, pfile)) { // error = EIO; goto err; } /* By definition, binary policy cannot have neverallow rules and all other rules are always loaded. */ (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS; (*policy)->options &= ~(QPOL_POLICY_OPTION_NO_RULES); if (policy_extend(*policy)) { error = errno; goto err; } } else if (qpol_module_create_from_file(path, &mod) == STATUS_SUCCESS) { (*policy)->type = retv = QPOL_POLICY_MODULE_BINARY; if (qpol_policy_append_module(*policy, mod)) { error = errno; goto err; } /* *policy now owns mod */ mod = NULL; if (qpol_policy_rebuild(*policy, options)) { error = errno; goto err; } } else { (*policy)->type = retv = QPOL_POLICY_KERNEL_SOURCE; fd = fileno(infile); if (fd < 0) { error = errno; goto err; } if (fstat(fd, &sb) < 0) { error = errno; ERR(*policy, "Can't stat '%s': %s\n", path, strerror(errno)); goto err; } qpol_src_input = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (qpol_src_input == MAP_FAILED) { error = errno; ERR(*policy, "Can't map '%s': %s\n", path, strerror(errno)); goto err; } qpol_src_inputptr = qpol_src_input; qpol_src_inputlim = &qpol_src_inputptr[sb.st_size - 1]; qpol_src_originalinput = qpol_src_input; /* store mmaped version for rebuild() */ (*policy)->file_data = qpol_src_originalinput; (*policy)->file_data_sz = sb.st_size; (*policy)->file_data_type = QPOL_POLICY_FILE_DATA_TYPE_MMAP; (*policy)->p->p.policy_type = POLICY_BASE; if (read_source_policy(*policy, "libqpol", (*policy)->options) < 0) { error = errno; goto err; } /* link the source */ INFO(*policy, "%s", "Linking source policy. (Step 2 of 5)"); if (sepol_link_modules((*policy)->sh, (*policy)->p, NULL, 0, 0)) { error = EIO; goto err; } avtab_destroy(&((*policy)->p->p.te_avtab)); avtab_destroy(&((*policy)->p->p.te_cond_avtab)); avtab_init(&((*policy)->p->p.te_avtab)); avtab_init(&((*policy)->p->p.te_cond_avtab)); if (prune_disabled_symbols(*policy)) { error = errno; goto err; } if (union_multiply_declared_symbols(*policy)) { error = errno; goto err; } /* expand */ if (qpol_expand_module(*policy, !(options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) { error = errno; goto err; } if (infer_policy_version(*policy)) { error = errno; goto err; } if (policy_extend(*policy)) { error = errno; goto err; } } fclose(infile); sepol_policy_file_free(pfile); return retv; err: qpol_policy_destroy(policy); qpol_module_destroy(&mod); sepol_policy_file_free(pfile); if (infile) fclose(infile); errno = error; return -1; } /** * @brief Internal version of qpol_policy_open_from_memory() version 1.3 * * Implementation of the exported function qpol_policy_open_from_memory() * for version 1.3; this symbol name is not exported. * @see qpol_policy_open_from_memory() */ int qpol_policy_open_from_memory(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn, void *varg, const int options) { int error = 0; if (policy == NULL || filedata == NULL) return -1; *policy = NULL; if (!(*policy = calloc(1, sizeof(qpol_policy_t)))) { error = errno; goto err; } (*policy)->options = options; /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */ if ((*policy)->options & QPOL_POLICY_OPTION_NO_RULES) (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS; (*policy)->sh = sepol_handle_create(); if ((*policy)->sh == NULL) { error = errno; ERR(*policy, "%s", strerror(error)); errno = error; return -1; } sepol_msg_set_callback((*policy)->sh, sepol_handle_route_to_callback, (*policy)); if (fn) { (*policy)->fn = fn; (*policy)->varg = varg; } else { (*policy)->fn = qpol_handle_default_callback; } if (sepol_policydb_create(&((*policy)->p))) { error = errno; goto err; } qpol_src_input = (char *)filedata; qpol_src_inputptr = qpol_src_input; qpol_src_inputlim = qpol_src_inputptr + size - 1; qpol_src_originalinput = qpol_src_input; /* store filedata for rebuild() */ if (!((*policy)->file_data = malloc(size))) { error = errno; goto err; } memcpy((*policy)->file_data, filedata, size); (*policy)->file_data_sz = size; (*policy)->file_data_type = QPOL_POLICY_FILE_DATA_TYPE_MEM; /* read in source */ (*policy)->p->p.policy_type = POLICY_BASE; if (read_source_policy(*policy, "parse", (*policy)->options) < 0) exit(1); /* link the source */ INFO(*policy, "%s", "Linking source policy. (Step 2 of 5)"); if (sepol_link_modules((*policy)->sh, (*policy)->p, NULL, 0, 0)) { error = EIO; goto err; } avtab_destroy(&((*policy)->p->p.te_avtab)); avtab_destroy(&((*policy)->p->p.te_cond_avtab)); avtab_init(&((*policy)->p->p.te_avtab)); avtab_init(&((*policy)->p->p.te_cond_avtab)); if (prune_disabled_symbols(*policy)) { error = errno; goto err; } if (union_multiply_declared_symbols(*policy)) { error = errno; goto err; } /* expand */ if (qpol_expand_module(*policy, !(options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) { error = errno; goto err; } return 0; err: qpol_policy_destroy(policy); errno = error; return -1; } void qpol_policy_destroy(qpol_policy_t ** policy) { if (policy != NULL && *policy != NULL) { sepol_policydb_free((*policy)->p); sepol_handle_destroy((*policy)->sh); if ((*policy)->modules) { size_t i = 0; for (i = 0; i < (*policy)->num_modules; i++) { qpol_module_destroy(&((*policy)->modules[i])); } free((*policy)->modules); } if ((*policy)->file_data_type == QPOL_POLICY_FILE_DATA_TYPE_MEM) { free((*policy)->file_data); } else if ((*policy)->file_data_type == QPOL_POLICY_FILE_DATA_TYPE_MMAP) { munmap((*policy)->file_data, (*policy)->file_data_sz); } free(*policy); *policy = NULL; } } int qpol_policy_reevaluate_conds(qpol_policy_t * policy) { policydb_t *db = NULL; cond_node_t *cond = NULL; cond_av_list_t *list_ptr = NULL; if (!policy) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (cond = db->cond_list; cond; cond = cond->next) { /* evaluate cond */ cond->cur_state = cond_evaluate_expr(db, cond->expr); if (cond->cur_state < 0) { ERR(policy, "Error evaluating conditional: %s", strerror(EILSEQ)); errno = EILSEQ; return STATUS_ERR; } /* walk true list */ for (list_ptr = cond->true_list; list_ptr; list_ptr = list_ptr->next) { /* field not used (except by write), * now storing list and enabled flags */ if (cond->cur_state) list_ptr->node->merged |= QPOL_COND_RULE_ENABLED; else list_ptr->node->merged &= ~(QPOL_COND_RULE_ENABLED); } /* walk false list */ for (list_ptr = cond->false_list; list_ptr; list_ptr = list_ptr->next) { /* field not used (except by write), * now storing list and enabled flags */ if (!cond->cur_state) list_ptr->node->merged |= QPOL_COND_RULE_ENABLED; else list_ptr->node->merged &= ~(QPOL_COND_RULE_ENABLED); } } return STATUS_SUCCESS; } int qpol_policy_append_module(qpol_policy_t * policy, qpol_module_t * module) { qpol_module_t **tmp = NULL; int error = 0; if (!policy || !module) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(tmp = realloc(policy->modules, (1 + policy->num_modules) * sizeof(qpol_module_t *)))) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } policy->modules = tmp; policy->modules[policy->num_modules] = module; policy->num_modules++; policy->modified = 1; module->parent = policy; return STATUS_SUCCESS; } typedef struct mod_state { qpol_module_t **list; size_t cur; size_t end; } mod_state_t; static int mod_state_end(const qpol_iterator_t * iter) { mod_state_t *ms; if (!iter || !(ms = qpol_iterator_state(iter))) { errno = EINVAL; return 1; } return (ms->cur >= ms->end); } static void *mod_state_get_cur(const qpol_iterator_t * iter) { mod_state_t *ms; if (!iter || !(ms = qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return ms->list[ms->cur]; } static int mod_state_next(qpol_iterator_t * iter) { mod_state_t *ms; if (!iter || !(ms = qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ms->cur++; return STATUS_SUCCESS; } static size_t mod_state_size(const qpol_iterator_t * iter) { mod_state_t *ms; if (!iter || !(ms = qpol_iterator_state(iter))) { errno = EINVAL; return 0; } return ms->end; } int qpol_policy_get_module_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { mod_state_t *ms = NULL; int error = 0; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(ms = calloc(1, sizeof(mod_state_t)))) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } if (qpol_iterator_create(policy, (void *)ms, mod_state_get_cur, mod_state_next, mod_state_end, mod_state_size, free, iter)) { error = errno; ERR(policy, "%s", strerror(error)); free(ms); errno = error; return STATUS_ERR; } ms->end = policy->num_modules; ms->list = policy->modules; return STATUS_SUCCESS; } static int is_mls_policy(const qpol_policy_t * policy) { policydb_t *db = NULL; if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; if (db->mls != 0) return 1; else return 0; } int qpol_policy_is_mls_enabled(qpol_policy_t * policy) { return is_mls_policy(policy); } int qpol_policy_get_policy_version(const qpol_policy_t * policy, unsigned int *version) { policydb_t *db; if (version != NULL) *version = 0; if (policy == NULL || version == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; *version = db->policyvers; return STATUS_SUCCESS; } int qpol_policy_get_policy_handle_unknown(const qpol_policy_t * policy, unsigned int *handle_unknown) { policydb_t *db; if (handle_unknown != NULL) *handle_unknown = 0; if (policy == NULL || handle_unknown == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; *handle_unknown = db->handle_unknown; return STATUS_SUCCESS; } int qpol_policy_get_target_platform(const qpol_policy_t *policy, int *target_platform) { policydb_t *db; if (target_platform != NULL) *target_platform = 0; if (policy == NULL || target_platform == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; *target_platform = db->target_platform; return STATUS_SUCCESS; } int qpol_policy_get_type(const qpol_policy_t * policy, int *type) { if (!policy || !type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *type = policy->type; return STATUS_SUCCESS; } int qpol_policy_has_capability(const qpol_policy_t * policy, qpol_capability_e cap) { unsigned int version = 0; if (!policy) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return 0; } qpol_policy_get_policy_version(policy, &version); switch (cap) { case QPOL_CAP_ATTRIB_NAMES: { if ((policy->type == QPOL_POLICY_KERNEL_SOURCE || policy->type == QPOL_POLICY_MODULE_BINARY) || (version >= 24)) return 1; break; } case QPOL_CAP_SYN_RULES: { if (policy->type == QPOL_POLICY_KERNEL_SOURCE || policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_LINE_NUMBERS: { if (policy->type == QPOL_POLICY_KERNEL_SOURCE) return 1; break; } case QPOL_CAP_CONDITIONALS: { if (version >= 16 || policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_MLS: { return is_mls_policy(policy); } case QPOL_CAP_MODULES: { if (policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_POLCAPS: { if (version >= 22 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 7 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_BOUNDS: { if (version >= 24 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 9 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_PERMISSIVE: { if (version >= 23 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 8 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_FILENAME_TRANS: { if (version >= 25 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 11 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_ROLETRANS: { if (version >= 26 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 12 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } /* This indicates the user, role and range - types were ate 28/16 */ case QPOL_CAP_DEFAULT_OBJECTS: { if (version >= 27 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 15 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_DEFAULT_TYPE: { if (version >= 28 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 16 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_XPERM_IOCTL: { if (version >= 30 && policy->type != QPOL_POLICY_MODULE_BINARY) return 1; if (version >= 17 && policy->type == QPOL_POLICY_MODULE_BINARY) return 1; break; } case QPOL_CAP_RULES_LOADED: { if (!(policy->options & QPOL_POLICY_OPTION_NO_RULES)) return 1; break; } case QPOL_CAP_SOURCE: { if (policy->type == QPOL_POLICY_KERNEL_SOURCE) return 1; break; } case QPOL_CAP_NEVERALLOW: { if (!(policy->options & QPOL_POLICY_OPTION_NO_NEVERALLOWS) && policy->type != QPOL_POLICY_KERNEL_BINARY) return 1; break; } default: { ERR(policy, "%s", "Unknown capability"); errno = EDOM; break; } } return 0; } setools-4.1.1/libqpol/policy_define.c000066400000000000000000003376731314142262400176460ustar00rootroot00000000000000/* * This file is a copy of policy_define.c from checkpolicy 2.6 updated to * support SETools. */ /* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: David Caplan, * * Added conditional policy language extensions * * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * 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 #include #include #include #include #include #include #include #include #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "module_compiler.h" #include "policy_define.h" /* Required for SETools libqpol - Removed #include "checkpolicy.h"*/ #include policydb_t *policydbp; queue_t id_queue = 0; unsigned int pass; char *curfile = 0; int mlspol = 0; /* Required for SETools libqpol */ int xenpol = 0; extern unsigned long policydb_lineno; extern unsigned long source_lineno; extern unsigned int policydb_errors; extern char source_file[PATH_MAX]; extern int yywarn(const char *msg); extern int yyerror(const 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; } __attribute__ ((format(printf, 1, 2))) void yyerror2(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(errormsg, ERRORMSG_LEN, fmt, ap); yyerror(errormsg); va_end(ap); } /* Required for SETools libqpol */ int define_mls(void) { mlspol = 1; policydbp->mls = 1; return 0; } /* Required for SETools libqpol */ int define_xen(void) { xenpol = 1; policydbp->target_platform = 1; return 0; } 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(const 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; } static int read_classes(ebitmap_t *e_classes) { char *id; class_datum_t *cladatum; while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (ebitmap_set_bit(e_classes, cladatum->s.value - 1, TRUE)) { yyerror("Out of memory"); return -1; } free(id); } return 0; } int define_default_user(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_user && cladatum->default_user != which) { yyerror2("conflicting default user information for class %s", id); return -1; } cladatum->default_user = which; free(id); } return 0; } int define_default_role(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_role && cladatum->default_role != which) { yyerror2("conflicting default role information for class %s", id); return -1; } cladatum->default_role = which; free(id); } return 0; } int define_default_type(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_type && cladatum->default_type != which) { yyerror2("conflicting default type information for class %s", id); return -1; } cladatum->default_type = which; free(id); } return 0; } int define_default_range(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_range && cladatum->default_range != which) { yyerror2("conflicting default range information for class %s", id); return -1; } cladatum->default_range = which; free(id); } return 0; } 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; uint32_t 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 __attribute__ ((unused)), 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; } free(id); 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; } free(id); 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) { free(id); if (!starallowed) { yyerror("* not allowed in this type of rule"); return -1; } /* set TYPE_STAR flag */ set->flags = TYPE_STAR; *add = 1; return 0; } if (strcmp(id, "~") == 0) { free(id); if (!starallowed) { yyerror("~ not allowed in this type of rule"); return -1; } /* complement the set */ set->flags = TYPE_COMP; *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; ebitmap_t tclasses; ebitmap_node_t *node; avrule_t *avrule; class_perm_node_t *perm; uint32_t i; int 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; avrule->source_line = source_lineno; avrule->source_filename = strdup(source_file); if (!avrule->source_filename) { yyerror("out of memory"); return -1; } while ((id = queue_remove(id_queue))) { if (set_types(&avrule->stypes, id, &add, 0)) goto bad; } add = 1; while ((id = queue_remove(id_queue))) { if (set_types(&avrule->ttypes, id, &add, 0)) goto bad; } ebitmap_init(&tclasses); if (read_classes(&tclasses)) goto bad; 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); free(id); goto bad; } free(id); 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"); goto bad; } class_perm_node_init(perm); perm->tclass = 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_tunable(int is_tunable) { 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)); if (is_tunable) datum->flags |= COND_BOOL_FLAGS_TUNABLE; 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?"); return -1; } datum->state = (int)(bool_value[0] == 'T') ? 1 : 0; free(bool_value); 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; } typedef struct av_ioctl_range { uint16_t low; uint16_t high; } av_ioctl_range_t; struct av_ioctl_range_list { uint8_t omit; av_ioctl_range_t range; struct av_ioctl_range_list *next; }; int avrule_sort_ioctls(struct av_ioctl_range_list **rangehead) { struct av_ioctl_range_list *r, *r2, *sorted, *sortedhead = NULL; /* order list by range.low */ for (r = *rangehead; r != NULL; r = r->next) { sorted = malloc(sizeof(struct av_ioctl_range_list)); if (sorted == NULL) goto error; memcpy(sorted, r, sizeof(struct av_ioctl_range_list)); sorted->next = NULL; if (sortedhead == NULL) { sortedhead = sorted; continue; } for (r2 = sortedhead; r2 != NULL; r2 = r2->next) { if (sorted->range.low < r2->range.low) { /* range is the new head */ sorted->next = r2; sortedhead = sorted; break; } else if ((r2 ->next != NULL) && (r->range.low < r2->next->range.low)) { /* insert range between elements */ sorted->next = r2->next; r2->next = sorted; break; } else if (r2->next == NULL) { /* range is the new tail*/ r2->next = sorted; break; } } } r = *rangehead; while (r != NULL) { r2 = r; r = r->next; free(r2); } *rangehead = sortedhead; return 0; error: yyerror("out of memory"); return -1; } int avrule_merge_ioctls(struct av_ioctl_range_list **rangehead) { struct av_ioctl_range_list *r, *tmp; r = *rangehead; while (r != NULL && r->next != NULL) { /* merge */ if ((r->range.high + 1) >= r->next->range.low) { /* keep the higher of the two */ if (r->range.high < r->next->range.high) r->range.high = r->next->range.high; tmp = r->next; r->next = r->next->next; free(tmp); continue; } r = r->next; } return 0; } int avrule_read_ioctls(struct av_ioctl_range_list **rangehead) { char *id; struct av_ioctl_range_list *rnew, *r = NULL; *rangehead = NULL; uint8_t omit = 0; /* read in all the ioctl commands */ while ((id = queue_remove(id_queue))) { if (strcmp(id,"~") == 0) { /* these are values to be omitted */ free(id); omit = 1; } else if (strcmp(id,"-") == 0) { /* high value of range */ free(id); id = queue_remove(id_queue); r->range.high = (uint16_t) strtoul(id,NULL,0); if (r->range.high < r->range.low) { yyerror("Ioctl ranges must be in ascending order."); return -1; } free(id); } else { /* read in new low value */ rnew = malloc(sizeof(struct av_ioctl_range_list)); if (rnew == NULL) goto error; rnew->next = NULL; if (*rangehead == NULL) { *rangehead = rnew; r = *rangehead; } else { r->next = rnew; r = r->next; } rnew->range.low = (uint16_t) strtoul(id,NULL,0); rnew->range.high = rnew->range.low; free(id); } } r = *rangehead; r->omit = omit; return 0; error: yyerror("out of memory"); return -1; } /* flip to included ranges */ int avrule_omit_ioctls(struct av_ioctl_range_list **rangehead) { struct av_ioctl_range_list *rnew, *r, *newhead, *r2; rnew = calloc(1, sizeof(struct av_ioctl_range_list)); if (!rnew) goto error; newhead = rnew; r = *rangehead; r2 = newhead; if (r->range.low == 0) { r2->range.low = r->range.high + 1; r = r->next; } else { r2->range.low = 0; } while (r) { r2->range.high = r->range.low - 1; rnew = calloc(1, sizeof(struct av_ioctl_range_list)); if (!rnew) goto error; r2->next = rnew; r2 = r2->next; r2->range.low = r->range.high + 1; if (!r->next) r2->range.high = 0xffff; r = r->next; } r = *rangehead; while (r != NULL) { r2 = r; r = r->next; free(r2); } *rangehead = newhead; return 0; error: yyerror("out of memory"); return -1; } int avrule_ioctl_ranges(struct av_ioctl_range_list **rangelist) { struct av_ioctl_range_list *rangehead; uint8_t omit; /* read in ranges to include and omit */ if (avrule_read_ioctls(&rangehead)) return -1; omit = rangehead->omit; if (rangehead == NULL) { yyerror("error processing ioctl commands"); return -1; } /* sort and merge the input ioctls */ if (avrule_sort_ioctls(&rangehead)) return -1; if (avrule_merge_ioctls(&rangehead)) return -1; /* flip ranges if these are ommited*/ if (omit) { if (avrule_omit_ioctls(&rangehead)) return -1; } *rangelist = rangehead; return 0; } int define_te_avtab_xperms_helper(int which, avrule_t ** rule) { char *id; class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL; class_datum_t *cladatum; perm_datum_t *perdatum = NULL; ebitmap_t tclasses; ebitmap_node_t *node; avrule_t *avrule; unsigned int i; int add = 1, ret = 0; avrule = (avrule_t *) malloc(sizeof(avrule_t)); if (!avrule) { yyerror("out of memory"); ret = -1; goto out; } avrule_init(avrule); avrule->specified = which; avrule->line = policydb_lineno; avrule->source_line = source_lineno; avrule->source_filename = strdup(source_file); avrule->xperms = NULL; if (!avrule->source_filename) { yyerror("out of memory"); return -1; } while ((id = queue_remove(id_queue))) { if (set_types (&avrule->stypes, id, &add, which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) { ret = -1; goto out; } } add = 1; while ((id = queue_remove(id_queue))) { if (strcmp(id, "self") == 0) { free(id); if (add == 0) { yyerror("-self is not supported"); ret = -1; goto out; } avrule->flags |= RULE_SELF; continue; } if (set_types (&avrule->ttypes, id, &add, which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) { ret = -1; goto out; } } ebitmap_init(&tclasses); ret = read_classes(&tclasses); if (ret) goto out; perms = NULL; id = queue_head(id_queue); 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->tclass = i + 1; if (!perms) perms = cur_perms; if (tail) tail->next = cur_perms; tail = cur_perms; cladatum = policydbp->class_val_to_struct[i]; perdatum = hashtab_search(cladatum->permissions.table, id); if (!perdatum) { if (cladatum->comdatum) { perdatum = hashtab_search(cladatum->comdatum-> permissions.table, id); } } if (!perdatum) { 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])) { 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); } } ebitmap_destroy(&tclasses); avrule->perms = perms; *rule = avrule; out: return ret; } /* index of the u32 containing the permission */ #define XPERM_IDX(x) (x >> 5) /* set bits 0 through x-1 within the u32 */ #define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1) /* low value for this u32 */ #define XPERM_LOW(x) (x << 5) /* high value for this u32 */ #define XPERM_HIGH(x) (((x + 1) << 5) - 1) void avrule_xperm_setrangebits(uint16_t low, uint16_t high, av_extended_perms_t *xperms) { unsigned int i; uint16_t h = high + 1; /* for each u32 that this low-high range touches, set driver permissions */ for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) { /* set all bits in u32 */ if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) xperms->perms[i] |= ~0U; /* set low bits */ else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i))) xperms->perms[i] |= XPERM_SETBITS(h); /* set high bits */ else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) xperms->perms[i] |= ~0U - XPERM_SETBITS(low); /* set middle bits */ else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i))) xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low); } } int avrule_xperms_used(av_extended_perms_t *xperms) { unsigned int i; for (i = 0; i < sizeof(xperms->perms)/sizeof(xperms->perms[0]); i++) { if (xperms->perms[i]) return 1; } return 0; } /* * using definitions found in kernel document ioctl-number.txt * The kernel components of an ioctl command are: * dir, size, driver, and fucntion. Only the driver and function fields * are considered here */ #define IOC_DRIV(x) (x >> 8) #define IOC_FUNC(x) (x & 0xff) #define IOC_CMD(driver, func) ((driver << 8) + func) int avrule_ioctl_partialdriver(struct av_ioctl_range_list *rangelist, av_extended_perms_t *complete_driver, av_extended_perms_t **extended_perms) { struct av_ioctl_range_list *r; av_extended_perms_t *xperms; uint8_t low, high; xperms = calloc(1, sizeof(av_extended_perms_t)); if (!xperms) { yyerror("out of memory"); return - 1; } r = rangelist; while(r) { low = IOC_DRIV(r->range.low); high = IOC_DRIV(r->range.high); if (complete_driver) { if (!xperm_test(low, complete_driver->perms)) xperm_set(low, xperms->perms); if (!xperm_test(high, complete_driver->perms)) xperm_set(high, xperms->perms); } else { xperm_set(low, xperms->perms); xperm_set(high, xperms->perms); } r = r->next; } if (avrule_xperms_used(xperms)) { *extended_perms = xperms; } else { free(xperms); *extended_perms = NULL; } return 0; } int avrule_ioctl_completedriver(struct av_ioctl_range_list *rangelist, av_extended_perms_t **extended_perms) { struct av_ioctl_range_list *r; av_extended_perms_t *xperms; uint16_t low, high; xperms = calloc(1, sizeof(av_extended_perms_t)); if (!xperms) { yyerror("out of memory"); return - 1; } r = rangelist; while(r) { /* * Any driver code that has sequence 0x00 - 0xff is a complete code, * * if command number = 0xff, then round high up to next code, * else 0x00 - 0xfe keep current code * of this range. temporarily u32 for the + 1 * to account for possible rollover before right shift */ high = IOC_DRIV((uint32_t) (r->range.high + 1)); /* if 0x00 keep current driver code else 0x01 - 0xff round up to next code*/ low = IOC_DRIV(r->range.low); if (IOC_FUNC(r->range.low)) low++; if (high > low) avrule_xperm_setrangebits(low, high - 1, xperms); r = r->next; } if (avrule_xperms_used(xperms)) { xperms->driver = 0x00; xperms->specified = AVRULE_XPERMS_IOCTLDRIVER; *extended_perms = xperms; } else { free(xperms); *extended_perms = NULL; } return 0; } int avrule_ioctl_func(struct av_ioctl_range_list *rangelist, av_extended_perms_t **extended_perms, unsigned int driver) { struct av_ioctl_range_list *r; av_extended_perms_t *xperms; uint16_t low, high; *extended_perms = NULL; xperms = calloc(1, sizeof(av_extended_perms_t)); if (!xperms) { yyerror("out of memory"); return - 1; } r = rangelist; /* for the passed in driver code, find the ranges that apply */ while (r) { low = r->range.low; high = r->range.high; if ((driver != IOC_DRIV(low)) && (driver != IOC_DRIV(high))) { r = r->next; continue; } if (driver == IOC_DRIV(low)) { if (high > IOC_CMD(driver, 0xff)) high = IOC_CMD(driver, 0xff); } else { if (low < IOC_CMD(driver, 0)) low = IOC_CMD(driver, 0); } low = IOC_FUNC(low); high = IOC_FUNC(high); avrule_xperm_setrangebits(low, high, xperms); xperms->driver = driver; xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION; r = r->next; } if (avrule_xperms_used(xperms)) { *extended_perms = xperms; } else { free(xperms); *extended_perms = NULL; } return 0; } void avrule_ioctl_freeranges(struct av_ioctl_range_list *rangelist) { struct av_ioctl_range_list *r, *tmp; r = rangelist; while (r) { tmp = r; r = r->next; free(tmp); } } unsigned int xperms_for_each_bit(unsigned int *bit, av_extended_perms_t *xperms) { unsigned int i; for (i = *bit; i < sizeof(xperms->perms)*8; i++) { if (xperm_test(i,xperms->perms)) { xperm_clear(i, xperms->perms); *bit = i; return 1; } } return 0; } int avrule_cpy(avrule_t *dest, avrule_t *src) { class_perm_node_t *src_perms; class_perm_node_t *dest_perms, *dest_tail; dest_tail = NULL; avrule_init(dest); dest->specified = src->specified; dest->flags = src->flags; if (type_set_cpy(&dest->stypes, &src->stypes)) { yyerror("out of memory"); return - 1; } if (type_set_cpy(&dest->ttypes, &src->ttypes)) { yyerror("out of memory"); return - 1; } dest->line = src->line; dest->source_filename = strdup(source_file); if (!dest->source_filename) { yyerror("out of memory"); return -1; } dest->source_line = src->source_line; /* increment through the class perms and copy over */ src_perms = src->perms; while (src_perms) { dest_perms = (class_perm_node_t *) calloc(1, sizeof(class_perm_node_t)); class_perm_node_init(dest_perms); if (!dest_perms) { yyerror("out of memory"); return -1; } if (!dest->perms) dest->perms = dest_perms; else dest_tail->next = dest_perms; dest_perms->tclass = src_perms->tclass; dest_perms->data = src_perms->data; dest_perms->next = NULL; dest_tail = dest_perms; src_perms = src_perms->next; } return 0; } int define_te_avtab_ioctl(avrule_t *avrule_template) { avrule_t *avrule; struct av_ioctl_range_list *rangelist; av_extended_perms_t *complete_driver, *partial_driver, *xperms; unsigned int i; /* organize ioctl ranges */ if (avrule_ioctl_ranges(&rangelist)) return -1; /* create rule for ioctl driver types that are entirely enabled */ if (avrule_ioctl_completedriver(rangelist, &complete_driver)) return -1; if (complete_driver) { avrule = (avrule_t *) calloc(1, sizeof(avrule_t)); if (!avrule) { yyerror("out of memory"); return -1; } if (avrule_cpy(avrule, avrule_template)) return -1; avrule->xperms = complete_driver; append_avrule(avrule); } /* flag ioctl driver codes that are partially enabled */ if (avrule_ioctl_partialdriver(rangelist, complete_driver, &partial_driver)) return -1; if (!partial_driver || !avrule_xperms_used(partial_driver)) goto done; /* * create rule for each partially used driver codes * "partially used" meaning that the code number e.g. socket 0x89 * has some permission bits set and others not set. */ i = 0; while (xperms_for_each_bit(&i, partial_driver)) { if (avrule_ioctl_func(rangelist, &xperms, i)) return -1; if (xperms) { avrule = (avrule_t *) calloc(1, sizeof(avrule_t)); if (!avrule) { yyerror("out of memory"); return -1; } if (avrule_cpy(avrule, avrule_template)) return -1; avrule->xperms = xperms; append_avrule(avrule); } } done: if (partial_driver) free(partial_driver); return 0; } int define_te_avtab_extended_perms(int which) { char *id; unsigned int i; avrule_t *avrule_template; if (pass == 1) { for (i = 0; i < 4; i++) { while ((id = queue_remove(id_queue))) free(id); } return 0; } /* populate avrule template with source/target/tclass */ if (define_te_avtab_xperms_helper(which, &avrule_template)) return -1; id = queue_remove(id_queue); if (strcmp(id,"ioctl") == 0) { free(id); if (define_te_avtab_ioctl(avrule_template)) return -1; } else { yyerror("only ioctl extended permissions are supported"); free(id); return -1; } return 0; } 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; avrule->source_line = source_lineno; avrule->source_filename = strdup(source_file); avrule->xperms = NULL; if (!avrule->source_filename) { yyerror("out of memory"); return -1; } 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); if (add == 0) { yyerror("-self is not supported"); ret = -1; goto out; } avrule->flags |= RULE_SELF; continue; } if (set_types (&avrule->ttypes, id, &add, which == AVRULE_NEVERALLOW ? 1 : 0)) { ret = -1; goto out; } } ebitmap_init(&tclasses); ret = read_classes(&tclasses); if (ret) goto out; 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->tclass = 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; } role = get_local_role(id, role->s.value, (role->flavor == ROLE_ATTRIB)); 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"); free(new); return NULL; } if (ebitmap_or(&new->types.types, &r1->types.types, &r2->types.types)) { yyerror("out of memory"); free(new); 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 __attribute__ ((unused)), 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; uint32_t 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) { if (read_classes(&e_classes)) return -1; } else { cladatum = hashtab_search(policydbp->p_classes.table, (hashtab_key_t)"process"); if (!cladatum) { yyerror2("could not find process class for " "legacy role_transition statement"); return -1; } if (ebitmap_set_bit(&e_classes, cladatum->s.value - 1, TRUE)) { yyerror("out of memory"); return -1; } } 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); free(id); goto bad; } if (role->flavor != ROLE_ROLE) { yyerror2("the new role %s must be a regular role", id); free(id); goto bad; } free(id); /* 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)) { free(ra); return -1; } } while ((id = queue_remove(id_queue))) { if (set_roles(&ra->new_roles, id)) { free(ra); 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_datum_t *ftdatum; filename_trans_rule_t *ftr; type_datum_t *typdatum; uint32_t otype; unsigned int c, s, t; int add, rc; 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); if (read_classes(&e_tclasses)) goto bad; 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; ft = calloc(1, sizeof(*ft)); if (!ft) { yyerror("out of memory"); goto bad; } ft->stype = s+1; ft->ttype = t+1; ft->tclass = c+1; ft->name = strdup(name); if (!ft->name) { yyerror("out of memory"); goto bad; } ftdatum = hashtab_search(policydbp->filename_trans, (hashtab_key_t)ft); if (ftdatum) { 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; } ftdatum = calloc(1, sizeof(*ftdatum)); if (!ftdatum) { yyerror("out of memory"); goto bad; } ftdatum->otype = otype; rc = hashtab_insert(policydbp->filename_trans, (hashtab_key_t)ft, ftdatum); if (rc) { yyerror("out of memory"); goto bad; } } } /* 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); if (type_set_cpy(&ftr->stypes, &stypes)) { yyerror("out of memory"); goto bad; } if (type_set_cpy(&ftr->ttypes, &ttypes)) { yyerror("out of memory"); goto bad; } 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"); free(node); 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"); free(node); 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: break; } yyerror("invalid constraint expression"); constraint_expr_destroy(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"); free(expr); 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 __attribute__ ((unused)), 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; } /* check context c to make sure ok to dereference c later */ if (c == NULL) { yyerror("null context pointer!"); return -1; } 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(uint64_t low, uint64_t 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%"PRIx64" exceeds high memory 0x%"PRIx64"", 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) { uint64_t low2, high2; low2 = c->u.iomem.low_iomem; high2 = c->u.iomem.high_iomem; if (low <= high2 && low2 <= high) { yyerror2("iomemcon entry for 0x%"PRIx64"-0x%"PRIx64" overlaps with " "earlier entry 0x%"PRIx64"-0x%"PRIx64"", 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%lx exceeds high ioport 0x%lx", 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) { uint32_t low2, high2; low2 = c->u.ioport.low_ioport; high2 = c->u.ioport.high_ioport; if (low <= high2 && low2 <= high) { yyerror2("ioportcon entry for 0x%lx-0x%lx 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%lx", device); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_PCIDEVICE] = newc; return 0; bad: free(newc); return -1; } int define_devicetree_context(void) { ocontext_t *newc, *c, *l, *head; if (policydbp->target_platform != SEPOL_TARGET_XEN) { yyerror("devicetreecon not supported for target"); return -1; } if (pass == 1) { free(queue_remove(id_queue)); 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.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; } head = policydbp->ocontexts[OCON_XEN_DEVICETREE]; for (l = NULL, c = head; c; l = c, c = c->next) { if (strcmp(newc->u.name, c->u.name) == 0) { yyerror2("duplicate devicetree entry for '%s'", newc->u.name); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_DEVICETREE] = newc; return 0; bad: free(newc->u.name); 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 if ((strcmp(id, "dccp") == 0) || (strcmp(id, "DCCP") == 0)) { protocol = IPPROTO_DCCP; } else { yyerror2("unrecognized protocol %s", id); goto bad; } 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); goto bad; } if (parse_security_context(&newc->context[0])) { goto bad; } /* 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; free(id); return 0; bad: free(id); 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(void) { 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)); #ifdef __APPLE__ memcpy(&newc->u.node6.addr[0], &addr.s6_addr[0], 16); memcpy(&newc->u.node6.mask[0], &mask.s6_addr[0], 16); #else memcpy(&newc->u.node6.addr[0], &addr.s6_addr32[0], 16); memcpy(&newc->u.node6.mask[0], &mask.s6_addr32[0], 16); #endif 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; } else { free(fstype); fstype = NULL; } 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)", genfs->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; free(type); 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) { if (read_classes(&rule->tclasses)) goto out; } else { cladatum = hashtab_search(policydbp->p_classes.table, (hashtab_key_t)"process"); if (!cladatum) { yyerror2("could not find process class for " "legacy range_transition statement"); goto out; } if (ebitmap_set_bit(&rule->tclasses, cladatum->s.value - 1, TRUE)) { yyerror("out of memory"); goto out; } } 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); free(rule); return -1; } /* FLASK */ setools-4.1.1/libqpol/policy_define.h000066400000000000000000000056231314142262400176360ustar00rootroot00000000000000/* * This file is a copy of policy_define.h from checkpolicy 2.4 updated to * support SETools. */ /* 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 /* Used by SETools to determine if source has MLS and/or XEN support */ int define_mls(void); int define_xen(void); 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_tunable(int is_tunable); int define_category(void); int define_class(void); int define_default_user(int which); int define_default_role(int which); int define_default_type(int which); int define_default_range(int which); 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(uint64_t low, uint64_t high); int define_ioport_context(unsigned long low, unsigned long high); int define_pcidevice_context(unsigned long device); int define_devicetree_context(void); 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_te_avtab_extended_perms(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(const 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_ */ setools-4.1.1/libqpol/policy_extend.c000066400000000000000000000341651314142262400176710ustar00rootroot00000000000000/** * @file * Implementation of the interface for loading and using an extended * policy image. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * @author Jeremy Solt jsolt@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #ifdef HAVE_SEPOL_ERRCODES #include #endif #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" struct extend_bogus_alias_struct { qpol_policy_t *q; int num_bogus_aliases; }; static int extend_find_bogus_alias(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *args) { struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args; /* within libqpol, qpol_type_t is the same a libsepol's type_datum_t */ qpol_type_t *qtype = (qpol_type_t *) datum; type_datum_t *type = (type_datum_t *) datum; unsigned char isalias; qpol_type_get_isalias(e->q, qtype, &isalias); return isalias && type->s.value == 0; } static void extend_remove_bogus_alias(hashtab_key_t key, hashtab_datum_t datum, void *args) { struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args; free(key); type_datum_t *type = (type_datum_t *) datum; type_datum_destroy(type); free(type); e->num_bogus_aliases++; } /** * Search the policy for aliases that have a value of 0. These come * from modular policies with disabled aliases, but end up being * written to the policy anyways due to a bug in libsepol. These * bogus aliases are removed from the policy. * @param policy Policy that may contain broken aliases. This policy * will be altered by this function. * @return 0 on success and < 0 on failure; if the call fails, errno * will be set. On failure, the policy state may be inconsistent. */ static int qpol_policy_remove_bogus_aliases(qpol_policy_t * policy) { policydb_t *db = NULL; if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; struct extend_bogus_alias_struct e = { policy, 0 }; hashtab_map_remove_on_error(db->p_types.table, extend_find_bogus_alias, extend_remove_bogus_alias, &e); #ifdef SETOOLS_DEBUG if (e.num_bogus_aliases > 0) { WARN(policy, "%s", "This policy contained disabled aliases; they have been removed."); } #endif return 0; } /** * Builds data for the attributes and inserts them into the policydb. * This function modifies the policydb. Names created for attributes * are of the form @ttr where value is the value of the attribute * as a four digit number (prepended with 0's as needed). * @param policy The policy from which to read the attribute map and * create the type data for the attributes. This policy will be altered * by this function. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set. On failure, the policy state may be inconsistent * especially in the case where the hashtab functions return the error. */ static int qpol_policy_build_attrs_from_map(qpol_policy_t * policy) { policydb_t *db = NULL; size_t i; uint32_t bit = 0, count = 0; ebitmap_node_t *node = NULL; type_datum_t *tmp_type = NULL, *orig_type; char *tmp_name = NULL, buff[10]; int error = 0, retv; INFO(policy, "%s", "Generating attributes for policy. (Step 4 of 5)"); if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return -1; } db = &policy->p->p; memset(&buff, 0, 10 * sizeof(char)); for (i = 0; i < db->p_types.nprim; i++) { /* skip types */ if (db->type_val_to_struct[i]->flavor == TYPE_TYPE) continue; count = 0; ebitmap_for_each_bit(&db->attr_type_map[i], node, bit) { if (ebitmap_node_get_bit(node, bit)) count++; } if (count == 0) { continue; } /* first create a new type_datum_t for the attribute, * with the attribute's type_list consisting of types * with this attribute */ /* Does not exist */ if (db->p_type_val_to_name[i] == NULL){ snprintf(buff, 9, "@ttr%04zd", i + 1); tmp_name = strdup(buff); if (!tmp_name) { error = errno; goto err; } } /* Already exists */ else tmp_name = db->p_type_val_to_name[i]; tmp_type = calloc(1, sizeof(type_datum_t)); if (!tmp_type) { error = errno; goto err; } tmp_type->primary = 1; tmp_type->flavor = TYPE_ATTRIB; tmp_type->s.value = i + 1; if (ebitmap_cpy(&tmp_type->types, &db->attr_type_map[i])) { error = ENOMEM; goto err; } /* now go through each of the member types, and set * their type_list bit to point back */ ebitmap_for_each_bit(&tmp_type->types, node, bit) { if (ebitmap_node_get_bit(node, bit)) { orig_type = db->type_val_to_struct[bit]; if (ebitmap_set_bit(&orig_type->types, tmp_type->s.value - 1, 1)) { error = ENOMEM; goto err; } } } /* Does not exist - insert new */ if (db->p_type_val_to_name[i] == NULL){ retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type); if (retv) { if (retv == SEPOL_ENOMEM) error = db->p_types.table ? ENOMEM : EINVAL; else error = EEXIST; goto err; } } /* Already exists - replace old */ else { retv = hashtab_replace(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type, NULL, NULL); if (retv) { if (retv == SEPOL_ENOMEM) error = db->p_types.table ? ENOMEM : EINVAL; else error = EEXIST; goto err; } } db->p_type_val_to_name[i] = tmp_name; db->type_val_to_struct[i] = tmp_type; /* memory now owned by symtab do not free */ tmp_name = NULL; tmp_type = NULL; } return STATUS_SUCCESS; err: free(tmp_name); type_datum_destroy(tmp_type); free(tmp_type); ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } /** * Builds data for empty attributes and inserts them into the policydb. * This function modifies the policydb. Names created for the attributes * are of the form @ttr where value is the value of the attribute * as a four digit number (prepended with 0's as needed). * @param policy The policy to which to add type data for attributes. * This policy will be altered by this function. * @return Returns 0 on success and < 0 on failure; if the call fails, * errno will be set. On failure, the policy state may be inconsistent * especially in the case where the hashtab functions return the error. */ static int qpol_policy_fill_attr_holes(qpol_policy_t * policy) { policydb_t *db = NULL; char *tmp_name = NULL, buff[10]; int error = 0, retv = 0; ebitmap_t tmp_bmap = { NULL, 0 }; type_datum_t *tmp_type = NULL; size_t i; if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; memset(&buff, 0, 10 * sizeof(char)); for (i = 0; i < db->p_types.nprim; i++) { if (db->type_val_to_struct[i]) continue; snprintf(buff, 9, "@ttr%04zd", i + 1); tmp_name = strdup(buff); if (!tmp_name) { error = errno; goto err; } tmp_type = calloc(1, sizeof(type_datum_t)); if (!tmp_type) { error = errno; goto err; } tmp_type->primary = 1; tmp_type->flavor = TYPE_ATTRIB; tmp_type->s.value = i + 1; tmp_type->types = tmp_bmap; retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type); if (retv) { if (retv == SEPOL_ENOMEM) error = db->p_types.table ? ENOMEM : EINVAL; else error = EEXIST; goto err; } db->p_type_val_to_name[i] = tmp_name; db->type_val_to_struct[i] = tmp_type; /* memory now owned by symtab do not free */ tmp_name = NULL; tmp_type = NULL; } return STATUS_SUCCESS; err: free(tmp_type); free(tmp_name); ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } static const char *const sidnames[] = { "undefined", "kernel", "security", "unlabeled", "fs", "file", "file_labels", "init", "any_socket", "port", "netif", "netmsg", "node", "igmp_packet", "icmp_socket", "tcp_socket", "sysctl_modprobe", "sysctl", "sysctl_fs", "sysctl_kernel", "sysctl_net", "sysctl_net_unix", "sysctl_vm", "sysctl_dev", "kmod", "policy", "scmp_packet", "devnull" }; /** * Uses names from flask to fill in the isid names which are not normally * saved. This function modified the policydb. * @param policy Policy to which to add sid names. * This policy will be altered by this function. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set. On failure, the policy state may be inconsistent. */ static int qpol_policy_add_isid_names(qpol_policy_t * policy) { policydb_t *db = NULL; ocontext_t *sid = NULL; uint32_t val = 0; int error = 0; if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (sid = db->ocontexts[OCON_ISID]; sid; sid = sid->next) { val = (uint32_t) sid->sid[0]; if (val > SECINITSID_NUM) val = 0; if (!sid->u.name) { sid->u.name = strdup(sidnames[val]); if (!sid->u.name) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } } } return 0; } /** * Walks the conditional list and adds links for reverse look up from * a te/av rule to the conditional from which it came. * @param policy The policy to which to add conditional trace backs. * This policy will be altered by this function. * @return 0 on success and < 0 on failure; if the call fails, * errno will be set. On failure, the policy state may be inconsistent. */ static int qpol_policy_add_cond_rule_traceback(qpol_policy_t * policy) { policydb_t *db = NULL; cond_node_t *cond = NULL; cond_av_list_t *list_ptr = NULL; qpol_iterator_t *iter = NULL; avtab_ptr_t rule = NULL; int error = 0; uint32_t rules = 0; INFO(policy, "%s", "Building conditional rules tables. (Step 5 of 5)"); if (!policy) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rules = (QPOL_RULE_ALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT); if (!(policy->options & QPOL_POLICY_OPTION_NO_NEVERALLOWS)) rules |= QPOL_RULE_NEVERALLOW; /* mark all unconditional rules as enabled */ if (qpol_policy_get_avrule_iter(policy, rules, &iter)) return STATUS_ERR; for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { if (qpol_iterator_get_item(iter, (void **)&rule)) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } rule->parse_context = NULL; rule->merged = QPOL_COND_RULE_ENABLED; } qpol_iterator_destroy(&iter); if (qpol_policy_get_terule_iter(policy, (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER), &iter)) return STATUS_ERR; for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { if (qpol_iterator_get_item(iter, (void **)&rule)) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } rule->parse_context = NULL; rule->merged = QPOL_COND_RULE_ENABLED; } qpol_iterator_destroy(&iter); for (cond = db->cond_list; cond; cond = cond->next) { /* evaluate cond */ cond->cur_state = cond_evaluate_expr(db, cond->expr); if (cond->cur_state < 0) { ERR(policy, "Error evaluating conditional: %s", strerror(EILSEQ)); errno = EILSEQ; return STATUS_ERR; } /* walk true list */ for (list_ptr = cond->true_list; list_ptr; list_ptr = list_ptr->next) { /* field not used after parse, now stores cond */ list_ptr->node->parse_context = (void *)cond; /* field not used (except by write), * now storing list and enabled flags */ list_ptr->node->merged = QPOL_COND_RULE_LIST; if (cond->cur_state) list_ptr->node->merged |= QPOL_COND_RULE_ENABLED; } /* walk false list */ for (list_ptr = cond->false_list; list_ptr; list_ptr = list_ptr->next) { /* field not used after parse, now stores cond */ list_ptr->node->parse_context = (void *)cond; /* field not used (except by write), * now storing list and enabled flags */ list_ptr->node->merged = 0; /* i.e. !QPOL_COND_RULE_LIST */ if (!cond->cur_state) list_ptr->node->merged |= QPOL_COND_RULE_ENABLED; } } return 0; } int policy_extend(qpol_policy_t * policy) { int retv, error; policydb_t *db = NULL; if (policy == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return -1; } db = &policy->p->p; retv = qpol_policy_remove_bogus_aliases(policy); if (retv) { error = errno; goto err; } if (db->attr_type_map) { retv = qpol_policy_build_attrs_from_map(policy); if (retv) { error = errno; goto err; } if (db->policy_type == POLICY_KERN) { retv = qpol_policy_fill_attr_holes(policy); if (retv) { error = errno; goto err; } } } retv = qpol_policy_add_isid_names(policy); if (retv) { error = errno; goto err; } if (policy->options & QPOL_POLICY_OPTION_NO_RULES) return STATUS_SUCCESS; retv = qpol_policy_add_cond_rule_traceback(policy); if (retv) { error = errno; goto err; } return STATUS_SUCCESS; err: /* no need to call ERR here as it will already have been called */ errno = error; return STATUS_ERR; } setools-4.1.1/libqpol/policy_parse.y000066400000000000000000001022751314142262400175400ustar00rootroot00000000000000/* * This file is a copy of policy_parse.y from checkpolicy 2.4 updated to * support SETools. */ /* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: David Caplan, * * Added conditional policy language extensions * * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * 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 */ %{ /* Required for SETools libqpol services */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" /* #include "checkpolicy.h" - Remove for SETools and replace with: */ #include #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(const char *msg); extern int yyerror(const char *msg); typedef int (* require_func_t)(int pass); /* Add for SETools libqpol */ /* redefine input so we can read from a string */ /* borrowed from O'Reilly lex and yacc pg 157 */ extern char qpol_src_input[]; extern char *qpol_src_inputptr;/* current position in qpol_src_input */ extern char *qpol_src_inputlim;/* end of data */ %} %union { unsigned int val; uint64_t val64; uintptr_t valptr; void *ptr; require_func_t require_func; } %type cond_expr cond_expr_prim cond_pol_list cond_else %type cond_allow_def cond_auditallow_def cond_auditdeny_def cond_dontaudit_def %type cond_transition_def cond_te_avtab_def cond_rule_def %type role_def roles %type cexpr cexpr_prim op role_mls_op %type ipv4_addr_def number %type number64 %type require_decl_def %token PATH %token QPATH %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 TUNABLE %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 ALLOWXPERM %token AUDITALLOWXPERM %token DONTAUDITXPERM %token NEVERALLOWXPERM %token SOURCE %token TARGET %token SAMEUSER %token FSCON PORTCON NETIFCON NODECON %token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON DEVICETREECON %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 %token DEFAULT_USER DEFAULT_ROLE DEFAULT_TYPE DEFAULT_RANGE %token LOW_HIGH LOW HIGH %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_default_rules 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_default_rules : default_rules | ; default_rules : default_user_def | default_role_def | default_type_def | default_range_def | default_rules default_user_def | default_rules default_role_def | default_rules default_type_def | default_rules default_range_def ; default_user_def : DEFAULT_USER names SOURCE ';' {if (define_default_user(DEFAULT_SOURCE)) return -1; } | DEFAULT_USER names TARGET ';' {if (define_default_user(DEFAULT_TARGET)) return -1; } ; default_role_def : DEFAULT_ROLE names SOURCE ';' {if (define_default_role(DEFAULT_SOURCE)) return -1; } | DEFAULT_ROLE names TARGET ';' {if (define_default_role(DEFAULT_TARGET)) return -1; } ; default_type_def : DEFAULT_TYPE names SOURCE ';' {if (define_default_type(DEFAULT_SOURCE)) return -1; } | DEFAULT_TYPE names TARGET ';' {if (define_default_type(DEFAULT_TARGET)) return -1; } ; default_range_def : DEFAULT_RANGE names SOURCE LOW ';' {if (define_default_range(DEFAULT_SOURCE_LOW)) return -1; } | DEFAULT_RANGE names SOURCE HIGH ';' {if (define_default_range(DEFAULT_SOURCE_HIGH)) return -1; } | DEFAULT_RANGE names SOURCE LOW_HIGH ';' {if (define_default_range(DEFAULT_SOURCE_LOW_HIGH)) return -1; } | DEFAULT_RANGE names TARGET LOW ';' {if (define_default_range(DEFAULT_TARGET_LOW)) return -1; } | DEFAULT_RANGE names TARGET HIGH ';' {if (define_default_range(DEFAULT_TARGET_HIGH)) return -1; } | DEFAULT_RANGE names TARGET LOW_HIGH ';' {if (define_default_range(DEFAULT_TARGET_LOW_HIGH)) return -1; } ; opt_mls : mls | ; mls : sensitivities dominance opt_categories levels mlspolicy ; sensitivities : sensitivity_def | sensitivities sensitivity_def ; /* SETools - Add define_mls() to set MLS, as we are working with * files only, not checkpolicy/module command line options */ sensitivity_def : SENSITIVITY identifier alias_def ';' {if (define_mls() | define_sens()) return -1;} | SENSITIVITY identifier ';' {if (define_mls() | 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 | tunable_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_tunable(0)) return -1; } ; tunable_def : TUNABLE identifier bool_val ';' { if (define_bool_tunable(1)) 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 | xperm_allow_def | xperm_auditallow_def | xperm_dontaudit_def | xperm_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; } ; xperm_allow_def : ALLOWXPERM names names ':' names identifier xperms ';' {if (define_te_avtab_extended_perms(AVRULE_XPERMS_ALLOWED)) return -1; } ; xperm_auditallow_def : AUDITALLOWXPERM names names ':' names identifier xperms ';' {if (define_te_avtab_extended_perms(AVRULE_XPERMS_AUDITALLOW)) return -1; } ; xperm_dontaudit_def : DONTAUDITXPERM names names ':' names identifier xperms ';' {if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; } ; xperm_neverallow_def : NEVERALLOWXPERM names names ':' names identifier xperms ';' {if (define_te_avtab_extended_perms(AVRULE_XPERMS_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 | dtree_context_def ; /* SETools - Add define_xen() to set policy type, as we are working * with files only, not checkpolicy/module command line options */ pirq_context_def : PIRQCON number security_context_def {if (define_xen() | define_pirq_context($2)) return -1;} ; iomem_context_def : IOMEMCON number64 security_context_def {if (define_xen() | define_iomem_context($2,$2)) return -1;} | IOMEMCON number64 '-' number64 security_context_def {if (define_xen() | define_iomem_context($2,$4)) return -1;} ; ioport_context_def : IOPORTCON number security_context_def {if (define_xen() | define_ioport_context($2,$2)) return -1;} | IOPORTCON number '-' number security_context_def {if (define_xen() | define_ioport_context($2,$4)) return -1;} ; pci_context_def : PCIDEVICECON number security_context_def {if (define_xen() | define_pcidevice_context($2)) return -1;} ; dtree_context_def : DEVICETREECON path security_context_def {if (define_xen() | define_devicetree_context()) 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; } ; xperms : xperm { if (insert_separator(0)) return -1; } | nested_xperm_set { if (insert_separator(0)) return -1; } | tilde xperm { if (insert_id("~", 0)) return -1; } | tilde nested_xperm_set { if (insert_id("~", 0)) return -1; if (insert_separator(0)) return -1; } ; nested_xperm_set : '{' nested_xperm_list '}' ; nested_xperm_list : nested_xperm_element | nested_xperm_list nested_xperm_element ; nested_xperm_element: xperm '-' { if (insert_id("-", 0)) return -1; } xperm | xperm | nested_xperm_set ; xperm : number { 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; } | QPATH { yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; } ; filename : FILENAME { yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; } ; number : NUMBER { $$ = strtoul(yytext,NULL,0); } ; number64 : NUMBER { $$ = strtoull(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; } | TUNABLE { $$ = require_tunable; } | SENSITIVITY { $$ = require_sens; } | CATEGORY { $$ = require_cat; } ; require_id_list : identifier { if ($0 (pass)) return -1; } | require_id_list ',' identifier { if ($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 */ ; setools-4.1.1/libqpol/policy_scan.l000066400000000000000000000210671314142262400173340ustar00rootroot00000000000000/* * This file is a copy of policy_scan.l from checkpolicy 2.4 updated to * support SETools. */ /* * Author : Stephen Smalley, */ /* Updated: David Caplan, * * Added conditional policy language extensions * * Jason Tang * * 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 */ /* Required for SETools libqpol services */ %{ #undef YY_INPUT #define YY_INPUT(b, r, ms) (r = qpol_src_yyinput(b, ms)) %} %{ #include #include #include #include typedef int (* require_func_t)(void); /* For SETools libqpol services leave this as policy_parse.h */ #include "policy_parse.h" static char linebuf[2][255]; static unsigned int lno = 0; int yywarn(const 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; /* These are required for SETools libqpol services */ /* redefine input so we can read from a string */ /* borrowed from O'Reilly lex and yacc pg 157 */ extern char qpol_src_input[]; extern char *qpol_src_inputptr;/* current position in myinput */ extern char *qpol_src_inputlim;/* end of data */ int qpol_src_yyinput(char *buf, int max_size); %} %option noinput nounput noyywrap %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); } TUNABLE | tunable { return(TUNABLE); } 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); } ALLOWXPERM | allowxperm { return(ALLOWXPERM); } AUDITALLOWXPERM | auditallowxperm { return(AUDITALLOWXPERM); } DONTAUDITXPERM | dontauditxperm { return(DONTAUDITXPERM); } NEVERALLOWXPERM | neverallowxperm { return(NEVERALLOWXPERM); } 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);} devicetreecon | DEVICETREECON { return(DEVICETREECON);} 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); } default_user | DEFAULT_USER { return(DEFAULT_USER); } default_role | DEFAULT_ROLE { return(DEFAULT_ROLE); } default_type | DEFAULT_TYPE { return(DEFAULT_TYPE); } default_range | DEFAULT_RANGE { return(DEFAULT_RANGE); } low-high | LOW-HIGH { return(LOW_HIGH); } high | HIGH { return(HIGH); } low | LOW { return(LOW); } "/"({alnum}|[_\.\-/])* { return(PATH); } \""/"[ !#-~]*\" { return(QPATH); } \"({alnum}|[_\.\-\+\~\: ])+\" { return(FILENAME); } {letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); } {digit}+|0x{hexval}+ { return(NUMBER); } {alnum}*{letter}{alnum}* { return(FILESYSTEM); } {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(const 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(const 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'; if (strlen(source_file) && source_file[strlen(source_file)-1] == '"') source_file[strlen(source_file)-1] = '\0'; } /* Required for SETools libqpol services */ int qpol_src_yyinput(char *buf, int max_size) { int n = max_size < (qpol_src_inputlim - qpol_src_inputptr) ? max_size : (qpol_src_inputlim - qpol_src_inputptr); if (n > 0) { memcpy(buf, qpol_src_inputptr, n); qpol_src_inputptr += n; } return n; } /* Required for SETools libqpol services */ void init_scanner(void) { yy_flush_buffer(YY_CURRENT_BUFFER); } setools-4.1.1/libqpol/portcon_query.c000066400000000000000000000107751314142262400177350ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over portcon statements. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" int qpol_policy_get_portcon_by_port(const qpol_policy_t * policy, uint16_t low, uint16_t high, uint8_t protocol, const qpol_portcon_t ** ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_PORT]; tmp; tmp = tmp->next) { if (tmp->u.port.low_port == low && tmp->u.port.high_port == high && tmp->u.port.protocol == protocol) break; } *ocon = (qpol_portcon_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find portcon statement for %u-%u:%u", low, high, protocol); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_portcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_PORT]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_portcon_get_protocol(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint8_t * protocol) { ocontext_t *internal_ocon = NULL; if (protocol != NULL) *protocol = 0; if (policy == NULL || ocon == NULL || protocol == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *protocol = internal_ocon->u.port.protocol; return STATUS_SUCCESS; } int qpol_portcon_get_low_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port) { ocontext_t *internal_ocon = NULL; if (port != NULL) *port = 0; if (policy == NULL || ocon == NULL || port == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *port = internal_ocon->u.port.low_port; return STATUS_SUCCESS; } int qpol_portcon_get_high_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port) { ocontext_t *internal_ocon = NULL; if (port != NULL) *port = 0; if (policy == NULL || ocon == NULL || port == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *port = internal_ocon->u.port.high_port; return STATUS_SUCCESS; } int qpol_portcon_get_context(const qpol_policy_t * policy, const qpol_portcon_t * ocon, const qpol_context_t ** context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) & (internal_ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/libqpol/qpol_internal.h000066400000000000000000000073251314142262400176750ustar00rootroot00000000000000/** * @file * Defines common debug symbols and the internal policy structure. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QPOL_INTERNAL_H #define QPOL_INTERNAL_H #ifdef __cplusplus extern "C" { #endif #include #include #include #define STATUS_SUCCESS 0 #define STATUS_ERR -1 #define STATUS_NODATA 1 #define QPOL_MSG_ERR 1 #define QPOL_MSG_WARN 2 #define QPOL_MSG_INFO 3 struct qpol_policy; struct qpol_module { char *name; char *path; char *version; int type; struct sepol_policydb *p; int enabled; struct qpol_policy *parent; }; struct qpol_policy { struct sepol_policydb *p; struct sepol_handle *sh; qpol_callback_fn_t fn; void *varg; int options; int type; int modified; struct qpol_module **modules; size_t num_modules; char *file_data; size_t file_data_sz; int file_data_type; }; /* qpol_policy_t.file_data_type will be one of the following to denote * the proper method of destroying the data: * _BIN if policy is from a binary source (modular or kernel) destroy is a no-op * _MMAP if policy is from a file and destroy should call munmap * _MEM if policy is from open_from_memory and destroy should call free */ #define QPOL_POLICY_FILE_DATA_TYPE_BIN 0 #define QPOL_POLICY_FILE_DATA_TYPE_MMAP 1 #define QPOL_POLICY_FILE_DATA_TYPE_MEM 2 /** * Create an extended image for a policy. This function modifies the policydb * by adding additional records and information about attributes, initial sids * and other components not normally written to a binary policy file. Subsequent * calls to this function have no effect. * @param policy The policy for which the extended image should be created. * @return Returns 0 on success and < 0 on failure. If the call fails, * errno will be set; the state of the policy is not guaranteed to be stable * if this call fails. */ int policy_extend(qpol_policy_t * policy); __attribute__ ((format(printf, 3, 4))) extern void qpol_handle_msg(const qpol_policy_t * policy, int level, const char *fmt, ...); int qpol_is_file_binpol(FILE * fp); int qpol_is_file_mod_pkg(FILE * fp); /** * Returns the version number of the binary policy. Note that this * will rewind the file pointer. * * @return Non-negative policy version, or -1 general error for, -2 * wrong magic number for file, or -3 problem reading file. */ int qpol_binpol_version(FILE * fp); /** * Returns true if the file is a module package. * @return Returns 1 for module packages, 0 otherwise. */ int qpol_is_data_mod_pkg(char * data); #define ERR(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_ERR, format, __VA_ARGS__) #define WARN(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_WARN, format, __VA_ARGS__) #define INFO(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_INFO, format, __VA_ARGS__) #ifdef __cplusplus } #endif #endif /* QPOL_INTERNAL_H */ setools-4.1.1/libqpol/queue.c000066400000000000000000000051401314142262400161360ustar00rootroot00000000000000/* * This file is a copy of queue.c from checkpolicy 2.4. There are * NO updates required to support SETools. */ /* Author : Stephen Smalley, */ /* FLASK */ /* * Implementation of the double-ended queue type. */ #include #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 */ setools-4.1.1/libqpol/queue.h000066400000000000000000000031461314142262400161470ustar00rootroot00000000000000/* * This file is a copy of queue.h from checkpolicy 2.4. There are * NO updates required to support SETools. */ /* Author : Stephen Smalley, */ /* 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 */ setools-4.1.1/libqpol/rbacrule_query.c000066400000000000000000000203741314142262400200440ustar00rootroot00000000000000/** * @file * Defines public interface for iterating over RBAC rules. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include "iterator_internal.h" #include "qpol_internal.h" #include typedef struct role_allow_state { role_allow_t *head; role_allow_t *cur; } role_allow_state_t; static int role_allow_state_end(const qpol_iterator_t * iter) { role_allow_state_t *ras = NULL; if (!iter || !(ras = qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ras->cur ? 0 : 1; } static void *role_allow_state_get_cur(const qpol_iterator_t * iter) { role_allow_state_t *ras = NULL; const policydb_t *db = NULL; if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_allow_state_end(iter)) { errno = EINVAL; return NULL; } return ras->cur; } static int role_allow_state_next(qpol_iterator_t * iter) { role_allow_state_t *ras = NULL; const policydb_t *db = NULL; if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } if (role_allow_state_end(iter)) { errno = ERANGE; return STATUS_ERR; } ras->cur = ras->cur->next; return STATUS_SUCCESS; } static size_t role_allow_state_size(const qpol_iterator_t * iter) { role_allow_state_t *ras = NULL; const policydb_t *db = NULL; role_allow_t *tmp = NULL; size_t count = 0; if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } for (tmp = ras->head; tmp; tmp = tmp->next) count++; return count; } int qpol_policy_get_role_allow_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; role_allow_state_t *ras = NULL; int error = 0; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ras = calloc(1, sizeof(role_allow_state_t)); if (!ras) { /* errno set by calloc */ ERR(policy, "%s", strerror(errno)); return STATUS_ERR; } ras->head = ras->cur = db->role_allow; if (qpol_iterator_create (policy, (void *)ras, role_allow_state_get_cur, role_allow_state_next, role_allow_state_end, role_allow_state_size, free, iter)) { error = errno; free(ras); errno = error; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_role_allow_get_source_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** source) { policydb_t *db = NULL; role_allow_t *ra = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ra = (role_allow_t *) rule; *source = (qpol_role_t *) db->role_val_to_struct[ra->role - 1]; return STATUS_SUCCESS; } int qpol_role_allow_get_target_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** target) { policydb_t *db = NULL; role_allow_t *ra = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; ra = (role_allow_t *) rule; *target = (qpol_role_t *) db->role_val_to_struct[ra->new_role - 1]; return STATUS_SUCCESS; } typedef struct role_trans_state { role_trans_t *head; role_trans_t *cur; } role_trans_state_t; static int role_trans_state_end(const qpol_iterator_t * iter) { role_trans_state_t *rts = NULL; if (!iter || !(rts = qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return rts->cur ? 0 : 1; } static void *role_trans_state_get_cur(const qpol_iterator_t * iter) { role_trans_state_t *rts = NULL; const policydb_t *db = NULL; if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_trans_state_end(iter)) { errno = EINVAL; return NULL; } return rts->cur; } static int role_trans_state_next(qpol_iterator_t * iter) { role_trans_state_t *rts = NULL; const policydb_t *db = NULL; if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } if (role_trans_state_end(iter)) { errno = ERANGE; return STATUS_ERR; } rts->cur = rts->cur->next; return STATUS_SUCCESS; } static size_t role_trans_state_size(const qpol_iterator_t * iter) { role_trans_state_t *rts = NULL; const policydb_t *db = NULL; role_trans_t *tmp = NULL; size_t count = 0; if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { errno = EINVAL; return STATUS_ERR; } for (tmp = rts->head; tmp; tmp = tmp->next) count++; return count; } int qpol_policy_get_role_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db = NULL; role_trans_state_t *rts = NULL; int error = 0; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rts = calloc(1, sizeof(role_trans_state_t)); if (!rts) { /* errno set by calloc */ ERR(policy, "%s", strerror(errno)); return STATUS_ERR; } rts->head = rts->cur = db->role_tr; if (qpol_iterator_create (policy, (void *)rts, role_trans_state_get_cur, role_trans_state_next, role_trans_state_end, role_trans_state_size, free, iter)) { error = errno; free(rts); errno = error; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_role_trans_get_source_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** source) { policydb_t *db = NULL; role_trans_t *rt = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (role_trans_t *) rule; *source = (qpol_role_t *) db->role_val_to_struct[rt->role - 1]; return STATUS_SUCCESS; } int qpol_role_trans_get_target_type(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_type_t ** target) { policydb_t *db = NULL; role_trans_t *rt = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (role_trans_t *) rule; *target = (qpol_type_t *) db->type_val_to_struct[rt->type - 1]; return STATUS_SUCCESS; } int qpol_role_trans_get_object_class(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_class_t ** obj_class) { policydb_t *db = NULL; role_trans_t *rt = NULL; if (obj_class) { *obj_class = NULL; } if (!policy || !rule || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (role_trans_t *) rule; *obj_class = (qpol_class_t *) db->class_val_to_struct[rt->tclass - 1]; return STATUS_SUCCESS; } int qpol_role_trans_get_default_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** dflt) { policydb_t *db = NULL; role_trans_t *rt = NULL; if (dflt) { *dflt = NULL; } if (!policy || !rule || !dflt) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; rt = (role_trans_t *) rule; *dflt = (qpol_role_t *) db->role_val_to_struct[rt->new_role - 1]; return STATUS_SUCCESS; } setools-4.1.1/libqpol/role_query.c000066400000000000000000000142471314142262400172100ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over roles. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include "iterator_internal.h" #include #include #include "qpol_internal.h" int qpol_policy_get_role_by_name(const qpol_policy_t * policy, const char *name, const qpol_role_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_roles.table, (hashtab_key_t)name); if (internal_datum == NULL) { *datum = NULL; ERR(policy, "could not find datum for role %s", name); errno = ENOENT; return STATUS_ERR; } *datum = (qpol_role_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_role_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_roles.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_role_get_value(const qpol_policy_t * policy, const qpol_role_t * datum, uint32_t * value) { role_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (role_datum_t *) datum; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_role_get_dominate_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** dominates) { role_datum_t *internal_datum = NULL; int error; ebitmap_state_t *es = NULL; if (policy == NULL || datum == NULL || dominates == NULL) { if (dominates != NULL) *dominates = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (role_datum_t *) datum; if (!(es = calloc(1, sizeof(ebitmap_state_t)))) { error = errno; ERR(policy, "%s", "unable to create iterator state object"); errno = error; return STATUS_ERR; } es->bmap = &internal_datum->dominates; if (qpol_iterator_create(policy, (void *)es, ebitmap_state_get_cur_role, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, dominates)) { error = errno; free(es); errno = error; return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*dominates); return STATUS_SUCCESS; } int qpol_role_get_type_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** types) { role_datum_t *internal_datum = NULL; policydb_t *db = NULL; ebitmap_t *expanded_set = NULL; int error; ebitmap_state_t *es = NULL; if (policy == NULL || datum == NULL || types == NULL) { if (types != NULL) *types = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (role_datum_t *) datum; db = &policy->p->p; if (!(expanded_set = calloc(1, sizeof(ebitmap_t)))) { error = errno; ERR(policy, "%s", "unable to create bitmap"); errno = error; return STATUS_ERR; } if (type_set_expand(&internal_datum->types, expanded_set, db, 1)) { ebitmap_destroy(expanded_set); free(expanded_set); ERR(policy, "error reading type set for role %s", db->p_role_val_to_name[internal_datum->s.value - 1]); errno = EIO; return STATUS_ERR; } if (!(es = calloc(1, sizeof(ebitmap_state_t)))) { error = errno; ERR(policy, "%s", "unable to create iterator state object"); ebitmap_destroy(expanded_set); free(expanded_set); errno = error; return STATUS_ERR; } es->bmap = expanded_set; es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, (void *)es, ebitmap_state_get_cur_type, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, ebitmap_state_destroy, types)) { error = errno; ebitmap_state_destroy(es); errno = error; return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*types); return STATUS_SUCCESS; } int qpol_role_get_name(const qpol_policy_t * policy, const qpol_role_t * datum, const char **name) { role_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (role_datum_t *) datum; *name = db->p_role_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } setools-4.1.1/libqpol/terule_query.c000066400000000000000000000142601314142262400175420ustar00rootroot00000000000000/** * @file * Implementation for the public interface for searching and iterating over type rules. * * @author Kevin Carr kcarr@tresys.com * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 "iterator_internal.h" #include #include #include #include #include #include #include #include "qpol_internal.h" int qpol_policy_get_terule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter) { policydb_t *db; avtab_state_t *state; if (iter) { *iter = NULL; } if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } #if 1 // Seems to make sediff/sediffx work better without breaking things if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) { ERR(policy, "%s", "Cannot get terules: Rules not loaded"); errno = ENOTSUP; return STATUS_ERR; } #endif db = &policy->p->p; state = calloc(1, sizeof(avtab_state_t)); if (state == NULL) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } state->ucond_tab = &db->te_avtab; state->cond_tab = &db->te_cond_avtab; state->rule_type_mask = rule_type_mask; state->node = db->te_avtab.htable[0]; if (qpol_iterator_create (policy, state, avtab_state_get_cur, avtab_state_next, avtab_state_end, avtab_state_size, free, iter)) { free(state); return STATUS_ERR; } if (state->node == NULL || !(state->node->key.specified & state->rule_type_mask)) { avtab_state_next(*iter); } return STATUS_SUCCESS; } int qpol_terule_get_source_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** source) { policydb_t *db = NULL; avtab_ptr_t terule = NULL; if (source) { *source = NULL; } if (!policy || !rule || !source) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; terule = (avtab_ptr_t) rule; *source = (qpol_type_t *) db->type_val_to_struct[terule->key.source_type - 1]; return STATUS_SUCCESS; } int qpol_terule_get_target_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** target) { policydb_t *db = NULL; avtab_ptr_t terule = NULL; if (target) { *target = NULL; } if (!policy || !rule || !target) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; terule = (avtab_ptr_t) rule; *target = (qpol_type_t *) db->type_val_to_struct[terule->key.target_type - 1]; return STATUS_SUCCESS; } int qpol_terule_get_object_class(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_class_t ** obj_class) { policydb_t *db = NULL; avtab_ptr_t terule = NULL; if (obj_class) { *obj_class = NULL; } if (!policy || !rule || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; terule = (avtab_ptr_t) rule; *obj_class = (qpol_class_t *) db->class_val_to_struct[terule->key.target_class - 1]; return STATUS_SUCCESS; } int qpol_terule_get_default_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** dflt) { policydb_t *db = NULL; avtab_ptr_t terule = NULL; if (dflt) { *dflt = NULL; } if (!policy || !rule || !dflt) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; terule = (avtab_ptr_t) rule; *dflt = (qpol_type_t *) db->type_val_to_struct[terule->datum.data - 1]; return STATUS_SUCCESS; } int qpol_terule_get_rule_type(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * rule_type) { avtab_ptr_t terule = NULL; if (rule_type) { *rule_type = 0; } if (!policy || !rule || !rule_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } terule = (avtab_ptr_t) rule; *rule_type = (terule->key.specified & (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER)); return STATUS_SUCCESS; } int qpol_terule_get_cond(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_cond_t ** cond) { avtab_ptr_t terule = NULL; if (cond) { *cond = NULL; } if (!policy || !rule || !cond) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } terule = (avtab_ptr_t) rule; *cond = (qpol_cond_t *) terule->parse_context; return STATUS_SUCCESS; } int qpol_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * is_enabled) { avtab_ptr_t terule = NULL; if (is_enabled) { *is_enabled = 0; } if (!policy || !rule || !is_enabled) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } terule = (avtab_ptr_t) rule; *is_enabled = ((terule->merged & QPOL_COND_RULE_ENABLED) ? 1 : 0); return STATUS_SUCCESS; } int qpol_terule_get_which_list(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * which_list) { avtab_ptr_t terule = NULL; if (which_list) { *which_list = 0; } if (!policy || !rule || !which_list) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } terule = (avtab_ptr_t) rule; if (!terule->parse_context) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *which_list = ((terule->merged & QPOL_COND_RULE_LIST) ? 1 : 0); return STATUS_SUCCESS; } setools-4.1.1/libqpol/type_query.c000066400000000000000000000272721314142262400172320ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over types. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "iterator_internal.h" #include #include "qpol_internal.h" int qpol_policy_get_type_by_name(const qpol_policy_t * policy, const char *name, const qpol_type_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_types.table, (hashtab_key_t)name); if (internal_datum == NULL) { *datum = NULL; ERR(policy, "could not find datum for type %s", name); errno = ENOENT; return STATUS_ERR; } *datum = (qpol_type_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_type_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_types.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_type_get_value(const qpol_policy_t * policy, const qpol_type_t * datum, uint32_t * value) { type_datum_t *internal_datum; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (type_datum_t *) datum; if (internal_datum->flavor == TYPE_ALIAS) { /* aliases that came from modules should use the value * referenced to by that alias */ *value = internal_datum->primary; } else { *value = internal_datum->s.value; } return STATUS_SUCCESS; } /** * Determine if a type_datum_t is an alias or a non-alias (primary * type or an attribute). For aliases declared in base policies, they * will have no primary value and a flavor of TYPE_TYPE. For aliases * declared in modules, they have a flavor of TYPE_ALIAS; their * primary value points to the new /linked/ type's value. * * @param datum Type datum to check. * * @return 1 if the datum is an alias, 0 if not. */ static int is_type_really_an_alias(const type_datum_t * datum) { if (datum->primary == 0 && datum->flavor == TYPE_TYPE) { return 1; } if (datum->flavor == TYPE_ALIAS) { return 1; } return 0; } int qpol_type_get_isalias(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isalias) { type_datum_t *internal_datum; if (policy == NULL || datum == NULL || isalias == NULL) { if (isalias != NULL) *isalias = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (type_datum_t *) datum; *isalias = is_type_really_an_alias(internal_datum); return STATUS_SUCCESS; } int qpol_type_get_isattr(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isattr) { type_datum_t *internal_datum; if (policy == NULL || datum == NULL || isattr == NULL) { if (isattr != NULL) *isattr = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (type_datum_t *) datum; *isattr = (internal_datum->flavor == TYPE_ATTRIB ? 1 : 0); return STATUS_SUCCESS; } int qpol_type_get_ispermissive(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *ispermissive) { if (policy == NULL || datum == NULL || ispermissive == NULL) { if (ispermissive != NULL) *ispermissive = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } #ifdef HAVE_SEPOL_PERMISSIVE_TYPES /* checking internal_datum->flags for permissive won't work, because the type could be an alias. so instead, look up its value within the permissive map */ uint32_t value; if (qpol_type_get_value(policy, datum, &value) < 0) { return STATUS_ERR; } policydb_t *p = &policy->p->p; /* note that unlike other bitmaps, this one does not subtract 1 in the bitmap */ *ispermissive = ebitmap_get_bit(&p->permissive_map, value); #else *ispermissive = 0; #endif return STATUS_SUCCESS; } int qpol_type_get_type_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** types) { type_datum_t *internal_datum = NULL; ebitmap_state_t *es = NULL; int error = 0; if (types != NULL) *types = NULL; if (policy == NULL || datum == NULL || types == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (type_datum_t *) datum; if (internal_datum->flavor != TYPE_ATTRIB) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_NODATA; } es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_datum->types); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, types)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*types); return STATUS_SUCCESS; } int qpol_type_get_attr_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** attrs) { type_datum_t *internal_datum = NULL; ebitmap_state_t *es = NULL; int error = 0; if (attrs != NULL) *attrs = NULL; if (policy == NULL || datum == NULL || attrs == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (type_datum_t *) datum; if (internal_datum->flavor == TYPE_ATTRIB) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_NODATA; } es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_datum->types); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, attrs)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*attrs); return STATUS_SUCCESS; } int qpol_type_get_name(const qpol_policy_t * policy, const qpol_type_t * datum, const char **name) { type_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (type_datum_t *) datum; *name = db->p_type_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } typedef struct type_alias_hash_state { unsigned int bucket; hashtab_node_t *node; hashtab_t *table; uint32_t val; } type_alias_hash_state_t; /** * For aliases that came from the base policy, their primary type is * referenced by s.value. For aliases that came from modules, their * primary type is referenced by the primary field. * * @param datum Alias whose primary value to get. * * @return The primary type's identifier. */ static uint32_t get_alias_primary(const type_datum_t * datum) { if (datum->flavor == TYPE_TYPE) { return datum->s.value; } else { return datum->primary; } } static int hash_state_next_type_alias(qpol_iterator_t * iter) { type_alias_hash_state_t *hs = NULL; type_datum_t *datum = NULL; if (iter == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (type_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } do { hash_state_next(iter); datum = hs->node ? (type_datum_t *) hs->node->datum : NULL; } while (datum != NULL && (hs->val != get_alias_primary(datum) || !is_type_really_an_alias(datum))); return STATUS_SUCCESS; } static void *hash_state_get_cur_alias(const qpol_iterator_t * iter) { type_alias_hash_state_t *hs = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } hs = (type_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return NULL; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return NULL; } return hs->node->key; } static size_t hash_alias_state_size(const qpol_iterator_t * iter) { type_alias_hash_state_t *hs = NULL; type_datum_t *tmp_datum; hashtab_node_t *tmp_node; uint32_t tmp_bucket = 0; size_t count = 0; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } hs = (type_alias_hash_state_t *) qpol_iterator_state(iter); for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { tmp_datum = tmp_node ? tmp_node->datum : NULL; if (tmp_datum) { if (hs->val == get_alias_primary(tmp_datum) && is_type_really_an_alias(tmp_datum)) { count++; } } } } return count; } int qpol_type_get_alias_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** aliases) { type_datum_t *internal_datum = NULL; policydb_t *db = NULL; int error = 0; type_alias_hash_state_t *hs = NULL; if (policy == NULL || datum == NULL || aliases == NULL) { if (aliases != NULL) *aliases = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (type_datum_t *) datum; hs = calloc(1, sizeof(type_alias_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_types.table; hs->node = (*(hs->table))->htable[0]; hs->val = get_alias_primary(internal_datum); if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias, hash_state_next_type_alias, hash_state_end, hash_alias_state_size, free, aliases)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || hs->val != get_alias_primary((type_datum_t *) (hs->node->datum)) || !is_type_really_an_alias((type_datum_t *) hs->node->datum)) hash_state_next_type_alias(*aliases); return STATUS_SUCCESS; } setools-4.1.1/libqpol/user_query.c000066400000000000000000000132451314142262400172220ustar00rootroot00000000000000/** * @file * Implementation of the interface for searching and iterating over users. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007 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 #include #include #include #include #include #include #include #include #include #include #include "iterator_internal.h" #include "qpol_internal.h" int qpol_policy_get_user_by_name(const qpol_policy_t * policy, const char *name, const qpol_user_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_users.table, (hashtab_key_t)name); if (internal_datum == NULL) { *datum = NULL; ERR(policy, "could not find datum for user %s", name); errno = ENOENT; return STATUS_ERR; } *datum = (qpol_user_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_user_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; hash_state_t *hs = NULL; int error = 0; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_users.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_user_get_value(const qpol_policy_t * policy, const qpol_user_t * datum, uint32_t * value) { user_datum_t *internal_datum; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (user_datum_t *) datum; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_user_get_role_iter(const qpol_policy_t * policy, const qpol_user_t * datum, qpol_iterator_t ** roles) { user_datum_t *internal_datum = NULL; int error = 0; ebitmap_state_t *es = NULL; if (policy == NULL || datum == NULL || roles == NULL) { if (roles != NULL) *roles = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (user_datum_t *) datum; es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_datum->roles.roles); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_role, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, roles)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*roles); return STATUS_SUCCESS; } int qpol_user_get_range(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_range_t ** range) { user_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || range == NULL) { if (range != NULL) *range = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!qpol_policy_has_capability(policy, QPOL_CAP_MLS)) { *range = NULL; } else { internal_datum = (user_datum_t *) datum; *range = (qpol_mls_range_t *) & internal_datum->exp_range; } return STATUS_SUCCESS; } int qpol_user_get_dfltlevel(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_level_t ** level) { user_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || level == NULL) { if (level != NULL) *level = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!qpol_policy_has_capability(policy, QPOL_CAP_MLS)) { *level = NULL; } else { internal_datum = (user_datum_t *) datum; *level = (qpol_mls_level_t *) & internal_datum->exp_dfltlevel; } return STATUS_SUCCESS; } int qpol_user_get_name(const qpol_policy_t * policy, const qpol_user_t * datum, const char **name) { user_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (user_datum_t *) datum; *name = db->p_user_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } setools-4.1.1/libqpol/xen_query.c000066400000000000000000000300101314142262400170230ustar00rootroot00000000000000/** * @file * Defines the public interface for searching and iterating over * Xen statements. * * @author Richard Haines richard_c_haines@btinternet.com * Derived from portcon_query.c * * 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. */ #include #include #include #include #include #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" #define __STDC_FORMAT_MACROS #include /******************************* iomemcon **************************/ int qpol_policy_get_iomemcon_by_addr(const qpol_policy_t *policy, uint64_t low, uint64_t high, const qpol_iomemcon_t **ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_XEN_IOMEM]; tmp; tmp = tmp->next) { if (tmp->u.iomem.low_iomem == low && tmp->u.iomem.high_iomem == high) break; } *ocon = (qpol_iomemcon_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find iomemcon statement for %" PRIu64 "-%" PRIu64, low, high); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_iomemcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_XEN_IOMEM]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_iomemcon_get_low_addr(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, uint64_t *addr) { ocontext_t *internal_ocon = NULL; if (addr != NULL) *addr = 0; if (policy == NULL || ocon == NULL || addr == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *addr = internal_ocon->u.iomem.low_iomem; return STATUS_SUCCESS; } int qpol_iomemcon_get_high_addr(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, uint64_t *addr) { ocontext_t *internal_ocon = NULL; if (addr != NULL) *addr = 0; if (policy == NULL || ocon == NULL || addr == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *addr = internal_ocon->u.iomem.high_iomem; return STATUS_SUCCESS; } int qpol_iomemcon_get_context(const qpol_policy_t *policy, const qpol_iomemcon_t *ocon, const qpol_context_t **context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) &(internal_ocon->context[0]); return STATUS_SUCCESS; } /******************************* ioportcon **************************/ int qpol_policy_get_ioportcon_by_port(const qpol_policy_t *policy, uint32_t low, uint32_t high, const qpol_ioportcon_t **ocon) { ocontext_t *tmp = NULL; policydb_t *db = NULL; if (ocon != NULL) *ocon = NULL; if (policy == NULL || ocon == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; for (tmp = db->ocontexts[OCON_XEN_IOPORT]; tmp; tmp = tmp->next) { if (tmp->u.ioport.low_ioport == low && tmp->u.ioport.high_ioport == high) break; } *ocon = (qpol_ioportcon_t *) tmp; if (*ocon == NULL) { ERR(policy, "could not find ioportcon statement for %u-%u", low, high); errno = ENOENT; return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_policy_get_ioportcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_XEN_IOPORT]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_ioportcon_get_low_port(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, uint32_t *port) { ocontext_t *internal_ocon = NULL; if (port != NULL) *port = 0; if (policy == NULL || ocon == NULL || port == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *port = internal_ocon->u.ioport.low_ioport; return STATUS_SUCCESS; } int qpol_ioportcon_get_high_port(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, uint32_t *port) { ocontext_t *internal_ocon = NULL; if (port != NULL) *port = 0; if (policy == NULL || ocon == NULL || port == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *port = internal_ocon->u.ioport.high_ioport; return STATUS_SUCCESS; } int qpol_ioportcon_get_context(const qpol_policy_t *policy, const qpol_ioportcon_t *ocon, const qpol_context_t **context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) &(internal_ocon->context[0]); return STATUS_SUCCESS; } /******************************* pcidevicecon **************************/ int qpol_policy_get_pcidevicecon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_XEN_PCIDEVICE]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_pcidevicecon_get_device(const qpol_policy_t *policy, const qpol_pcidevicecon_t *ocon, uint32_t *device) { ocontext_t *internal_ocon = NULL; if (device != NULL) *device = 0; if (policy == NULL || ocon == NULL || device == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *device = internal_ocon->u.device; return STATUS_SUCCESS; } int qpol_pcidevicecon_get_context(const qpol_policy_t *policy, const qpol_pcidevicecon_t *ocon, const qpol_context_t **context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) &(internal_ocon->context[0]); return STATUS_SUCCESS; } /******************************* pirqcon **************************/ int qpol_policy_get_pirqcon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db = NULL; int error = 0; ocon_state_t *os = NULL; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_XEN_PIRQ]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_pirqcon_get_irq(const qpol_policy_t *policy, const qpol_pirqcon_t *ocon, uint16_t *irq) { ocontext_t *internal_ocon = NULL; if (irq != NULL) *irq = 0; if (policy == NULL || ocon == NULL || irq == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *irq = internal_ocon->u.pirq; return STATUS_SUCCESS; } int qpol_pirqcon_get_context(const qpol_policy_t *policy, const qpol_pirqcon_t *ocon, const qpol_context_t **context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) &(internal_ocon->context[0]); return STATUS_SUCCESS; } /******************************* devicetreecon **************************/ int qpol_policy_get_devicetreecon_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) { policydb_t *db = NULL; ocon_state_t *os = NULL; int error = 0; if (iter != NULL) *iter = NULL; if (policy == NULL || iter == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; os = calloc(1, sizeof(ocon_state_t)); if (os == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } os->head = os->cur = db->ocontexts[OCON_XEN_DEVICETREE]; if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur, ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) { free(os); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_devicetreecon_get_path(const qpol_policy_t *policy, const qpol_devicetreecon_t *ocon, char **path) { ocontext_t *internal_ocon = NULL; if (path != NULL) *path = NULL; if (policy == NULL || ocon == NULL || path == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *path = internal_ocon->u.name; return STATUS_SUCCESS; } int qpol_devicetreecon_get_context(const qpol_policy_t *policy, const qpol_devicetreecon_t *ocon, const qpol_context_t **context) { ocontext_t *internal_ocon = NULL; if (context != NULL) *context = NULL; if (policy == NULL || ocon == NULL || context == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_ocon = (ocontext_t *) ocon; *context = (qpol_context_t *) &(internal_ocon->context[0]); return STATUS_SUCCESS; } setools-4.1.1/man/000077500000000000000000000000001314142262400137575ustar00rootroot00000000000000setools-4.1.1/man/apol.1000066400000000000000000000024241314142262400147760ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH apol 1 2016-02-20 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME apol \- Graphical SELinux policy analysis tool .SH SYNOPSIS \fBapol\fR [OPTIONS] [POLICY] .SH DESCRIPTION .PP \fBapol\fR is a graphical tool that allows the user to inspect and analyze aspects of an SELinux policy. .SH POLICY .PP \fBapol\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP If not provided, \fBapol\fR will start with none loaded. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO sediff(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.1.1/man/sediff.1000066400000000000000000000107721314142262400153100ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sediff 1 2016-04-19 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME sediff \- SELinux policy difference tool .SH SYNOPSIS \fBsediff\fR [OPTIONS] [EXPRESSION] POLICY1 POLICY2 .SH DESCRIPTION Determine the differences between two SELinux policies. .SH POLICY .PP \fBsediff\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP Policies do not need to be the same format. If not provided, \fBsediff\fR will print an error message and exit. .SH EXPRESSIONS .P The user may specify an expression listing the policy elements to differentiate. If not provided, all supported policy elements are examined. .SS Component Differences .IP "--common" Find differences in common permission sets. .IP "-c, --class" Find differences in object classes. .IP "-t, --type" Find differences in attributes associated with types. .IP "-a, --attribute" Find differences in types assigned to attributes. .IP "-r, --role" Find differences in types authorized for roles. .IP "-u, --user" Find differences in roles authorized for users. .IP "-b, --bool" Find differences in the default values of booleans. .IP "--sensitivity" Find differences in sensitivity definitions. .IP "--category" Find differences in category definitions. .IP "--level" Find differences in MLS level definitions. .SS Type Enforcement Rule Differences .IP "-A" Find differences in allow and allowxperm rules. .IP "--allow" Find differences in allow rules. .IP "--auditallow" Find differences in auditallow rules. .IP "--dontaudit" Find differences in dontaudit rules. .IP "--neverallow" Find differences in neverallow rules. .IP "--allowxperm" Find differences in allowxperm rules. .IP "--auditallowxperm" Find differences in auditallowxperm rules. .IP "--dontauditxperm" Find differences in dontauditxperm rules. .IP "--neverallowxperm" Find differences in neverallowxperm rules. .IP "-T, --type_trans" Find differences in type_transition rules. .IP "--type_member" Find differences in type_member rules. .IP "--type_change" Find differences in type_change rules. .SS RBAC Rule Differences .IP "--role_allow" Find differences in role allow rules. .IP "--role_trans" Find differences in role_transition rules. .SS MLS Rule Differences .IP "--range_trans" Find differences in range_transition rules. .SS Constraint Differences .IP "--constrain" Find differences in constrain rules. .IP "--mlsconstrain" Find differences in mlsconstrain rules. .IP "--validatetrans" Find differences in validatetrans rules. .IP "--mlsvalidatetrans" Find differences in mlsvalidatetrans rules. .SS Labeling Statement Differences .IP "--initialsid" Find differences in initial SID statements. .IP "--fs_use" Find differences in fs_use_* statements. .IP "--genfscon" Find differences in genfscon statements. .IP "--netifcon" Find differences in netifcon statements. .IP "--nodecon" Find differences in nodecon statements. .IP "--portcon" Find differences in portcon statements. .SS Other Differences .IP "--default" Find differences in default_* statements. .IP "--property" Find differences in policy properties. Only applicable for binary policies (policy version, MLS enabled/disabled, unknown permissions setting). .IP "--polcap" Find differences in policy capabilities. .IP "--typebounds" Find differences in typebound statements. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--stats" Print difference statistics only. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH DIFFERENCES .PP .B sediff categorizes differences in policy elements into one of three forms. .RS .IP "added" The element exists only in the modified policy. .IP "removed" The element exists only in the original policy. .IP "modified" The element exists in both policies but its semantic meaning has changed. For example, a class is modified if one or more permissions are added or removed. .RE .PP .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO apol(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.1.1/man/sedta.1000066400000000000000000000055201314142262400151430ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sedta 1 2016-02-20 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME sedta \- Domain transition analysis for SELinux policies .SH SYNOPSIS \fBsedta\fR [OPTIONS] -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH DESCRIPTION .PP \fBsedta\fR is a command line tool that allows the user to perform domain transition analyses on an SELinux policy. .SH POLICY .PP \fBsedta\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP .PP If no policy file is provided, \fBsedta\fR will search for the policy running on the current system. If no policy can be found, \fBsedta\fR will print an error message and exit. .SH OPTIONS .SS Analysis Settings .IP "-p POLICY" Specify the policy to analyze. If none is specified, \fBsedta\fR will search for the policy running on the current system. .IP "-s SOURCE" Specify the source type to use in the domain transition analysis. .IP "-t TARGET" Specify the target type to use in the domain transition analysis. Using this option will also require specifying an analysis algorithm. .SS Analysis Algorithms \fBsedta\fR uses graph algorithms to analyze the domain transition paths of an SELinux policy. The following algorithms are options for determining paths from a source type to a target type. .IP "-S" Print the shortest domain transition path(s) from the source type to the target type. If multiple paths have the same length, all will be displayed. .IP "-A LIMIT" Print all domain transition path(s) up to LIMIT steps long. Depending on the connectiveness of the policy, this may be extremely expensive. .SS Analysis Options .IP -r Perform a reverse domain transition analysis. The domain transitions will be analyzed to find the the parent domains, instead of finding the child domains. .IP "-l LIMIT_TRANS" Specify the maximum number of domain transitions to output. The default is unlimited. .IP EXCLUDE A space-separated list of types to exclude from the analysis. .SS General Options .IP "--stats" Print domain transition graph statistics at the end of the analysis. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO apol(1), sediff(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.1.1/man/seinfo.1000066400000000000000000000131131314142262400153230ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfo 1 2016-02-20 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME seinfo \- SELinux policy information tool .SH SYNOPSIS \fBseinfo\fR [OPTIONS] [EXPRESSION] [POLICY] .SH DESCRIPTION \fBseinfo\fR allows the user to query the components of a SELinux policy. .SH POLICY .PP \fBapol\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP If no policy file is provided, \fBseinfo\fR will search for the policy running on the current system. If no policy can be found, \fBseinfo\fR will print an error message and exit. .SH EXPRESSIONS .P One or more of the following component types can be queried. If no expressions are provided, policy statistics will be printed. .IP "-a [ATTR], --attribute [ATTR]" Print a list of type attributes or, if ATTR is provided, print the named attribute. With \fI-x\fR, print a list of types assigned to each displayed attribute. .IP "-b [BOOL], --bool [BOOL]" Print a list of Booleans or, if BOOL is provided, print the named boolean. With \fI-x\fR, print the statement of each displayed conditional boolean. .IP "-c [CLASS], --class [CLASS]" Print a list of object classes or, if CLASS is provided, print the named object class. With \fI-x\fR, print a list of permissions for each displayed object class. .IP "-r [ROLE], --role [ROLE]" Print a list of roles or, if NAME is provided, print the named role. With \fI-x\fR, print the statement for each displayed role. .IP "-t [TYPE], --type [TYPE]" Print a list of types or, if TYPE is provided, print the named type. With \fI-x\fR, print a list of attributes which include each displayed type. .IP "-u [USER], --user [USER]" Print a list of users or, if USER is provided, print the named user. With \fI-x\fR, print a list of statement for each displayed user. .IP "--category [CAT]" Print a list of categories or, if CAT is provided, print the named category. With \fI-x\fR, print a list of sensitivities with which each displayed category may be associated. .IP "--common [COMMON]" Print a list of common permission sets or, if COMMON is provided, print the named common. With \fI-x\fR, print a list of permissions in the set. .IP "--constrain [CLASS]" Print a list of constraints and MLS constraints statements or, if CLASS is provided, print all constraints for the named object class. There is no expanded information for this component. .IP "--default [CLASS]" Print a list of default_* statements or, if CLASS is provided, print all default_* statements for the named object class. There is no expanded information for this component. .IP "--fs_use [FS_TYPE]" Print a list of fs_use_* statements or, if FS_TYPE is provided, print the statement for the named filesystem type. There is no expanded information for this component. .IP "--genfscon [FS_TYPE]" Print a list of genfscon statements or, if FS_TYPE is provided, print the statement for the named filesystem type. There is no expanded information for this component. .IP "--initialsid [NAME]" Print a list of initial SIDs or, if NAME is provided, print the named initial SID. With \fI-x\fR, print the context assigned to each displayed SID. .IP "--netifcon [DEVICE]" Print a list of netif contexts or, if DEVICE is provided, print the named statement for the interface. There is no expanded information for this component. .IP "--nodecon [ADDR]" Print a list of node contexts or, if ADDR is provided, print the named statement for the node with address. There is no expanded information for this component. .IP "--permissive [TYPE]" Print permissive types or, if TYPE is specified, print the named statement if it is permissive. There is no expanded information for this component. .IP "--polcap [NAME]" Print policy capabilities or, if NAME is specified, print the named capability, if enabled. With \fI-x\fR, print the statement. .IP "--portcon [PORTNUM[-PORTNUM]]" Print a list of port contexts or, if PORT or PORT range is provided, print the named statement for the port/port range. There is no expanded information for this component. .IP "--sensitivity [SENS]" Print a list of sensitivities or, if SENS is provided, print the named sensitivity. With \fI-x\fR, print the statement for each sensitivity. .IP "--typebounds [BOUND_TYPE]" Print a list of typebounds statements or, if BOUND_TYPE is provided, print the statement for the named bound type. There is no expanded information for this component. .IP "--validatetrans [CLASS]" Print a list of validatetrans and MLS validatetrans rules or, if CLASS is provided, print all constraints for the named object class. There is no expanded information for this component. .IP "--all" Print all components. .SH OPTIONS .IP "-x, --expand" Print additional details for each component matching the expression. See the description of each component for the details this option will provide. .IP "--flat" Exclude headers and indentation in output. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfoflow(1), sesearch(1) setools-4.1.1/man/seinfoflow.1000066400000000000000000000056651314142262400162300ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfoflow 1 2016-02-20 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME seinfoflow \- Information flow analysis for SELinux policies .SH SYNOPSIS \fBseinfoflow\fR [OPTIONS] -m MAP -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH DESCRIPTION .PP \fBseinfoflow\fR is a command line tool that allows the user to perform information flow analyses on an SELinux policy. .SH POLICY .PP \fBseinfoflow\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP .PP If no policy file is provided, \fBseinfoflow\fR will search for the policy running on the current system. If no policy can be found, \fBseinfoflow\fR will print an error message and exit. .SH OPTIONS .SS Analysis Settings .IP "-p POLICY" Specify the policy to analyze. If none is specified, \fBseinfoflow\fR will search for the policy running on the current system. .IP "-m MAP" Specify the path to the permission map file to use in the information flow analysis. .IP "-s SOURCE" Specify the source type to use in the information flow analysis. .IP "-t TARGET" Specify the target type to use in the information flow analysis. Using this option will also require specifying an analysis algorithm. .SS Analysis Algorithms \fBseinfoflow\fR uses graph algorithms to analyze the information flow paths of an SELinux policy. The following algorithms are options for determining paths from a source type to a target type. .IP "-S" Print the shortest information flow path(s) from the source type to the target type. If multiple paths have the same length, all will be displayed. .IP "-A LIMIT" Print all information flow path(s) up to LIMIT steps long. Depending on the connectiveness of the policy, a limit of 5 or more may be extremely expensive. .SS Analysis Options .IP "-w MIN_WEIGHT" Specify the minimum permission weight to consider for the analysis (1-10). The default is 3. .IP "-l LIMIT_FLOWS" Specify the maximum number of information flows to output. The default is unlimited. .IP EXCLUDE A space-separated list of types to exclude from the analysis. .SS General Options .IP "--stats" Print information flow graph statistics at the end of the analysis. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfo(1), sesearch(1) setools-4.1.1/man/sesearch.1000066400000000000000000000077601314142262400156500ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sesearch 1 2016-04-19 "Tresys Technology, LLC" "SETools: SELinux Policy Analysis Tools" .SH NAME sesearch \- SELinux policy query tool .SH SYNOPSIS \fBsesearch\fR [OPTIONS] [OPTIONS] [EXPRESSION] [POLICY] .SH DESCRIPTION \fBsesearch\fR allows the user to search the rules in a SELinux policy. .SH POLICY .PP \fBsesearch\fR supports loading SELinux policies in one of two formats. .RS .IP "source:" A single text file containing a monolithic policy source. This file is usually named policy.conf. .IP "binary:" A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. .RE .PP If no policy file is provided, \fBsesearch\fR will search for the policy running on the current system. If no policy can be found, \fBsesearch\fR will print an error message and exit. .SH EXPRESSIONS The user may specify an expression containing values for a given field(s) in a rule. If no expression is specified or if none of the specified fields apply to a given rule type, all rules of that type are considered to match the expression. .SS Type Enforcement Rule Types .IP "-A" Find allow and allowxperm rules. .IP "--allow" Find allow rules. .IP "--auditallow" Find auditallow rules. .IP "--dontaudit" Find dontaudit rules. .IP "--neverallow" Find neverallow rules. .IP "--allowxperm" Find allowxperm rules. .IP "--auditallowxperm" Find auditallowxperm rules. .IP "--dontauditxperm" Find dontauditxperm rules. .IP "--neverallowxperm" Find neverallowxperm rules. .IP "-T, --type_trans" Find type_transition rules. .IP "--type_member" Find type_member rules. .IP "--type_change" Find type_change rules. .SS RBAC Rule Types .IP "--role_allow" Find role allow rules. .IP "--role_trans" Find role_transition rules. .SS MLS Rule Types .IP "--range_trans" Find range_transition rules. .SS Rule Fields .IP "-s NAME, --source NAME" Find rules with NAME as their source type/role. .IP "-t NAME, --target NAME" Find rules with NAME as their target type/role. .IP "-D NAME, --default NAME" Find rules with NAME as their default type/role/level. .IP "-c NAME, --class NAME" Find rules with NAME as their object class. .IP "-p P1[,P2,...] --perm P1[,P2...]" Find rules with at least one of the specified permissions. Multiple permissions may be specified as a comma-separated list. .IP "-b BOOL[,B2,...], --bool BOOL[,B2,...]" Find conditional rules with the named Boolean in their conditional expression. Multiple Booleans may be specified as a comma-separated list. This option will include rules in both the true and false lists of the conditional. .SS Search Options The following additional options modify how the search is performed. .IP "-ds" A matching rule must have the specified source attribute/type/role explicitly, instead of matching by attribute contents. .IP "-dt" A matching rule must have the specified target attribute/type/role explicitly, instead of matching by attribute contents. .IP "-eb" A matching rule must have all specified Booleans, instead of matching any of the specified Boolean. .IP "-ep" A matching rule must have all specified permissions, instead of matching any of the specified permission. .IP "-rs" Use regular expression for matching the source type/role. .IP "-rt" Use regular expression for matching the target type/role. .IP "-rc" Use regular expression for matching the object class. .IP "-rd" Use regular expression for matching the default type/role. .IP "-rb" Use regular expression for matching Booleans. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/TresysTechnology/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfo(1), seinfoflow(1) setools-4.1.1/patches/000077500000000000000000000000001314142262400146335ustar00rootroot00000000000000setools-4.1.1/patches/README000066400000000000000000000001141314142262400155070ustar00rootroot00000000000000If there is a bug in one of SETools' dependencies, patches can be put here. setools-4.1.1/patches/explicit-python3.diff000066400000000000000000000025611314142262400207140ustar00rootroot00000000000000diff --git a/apol b/apol index c3e58f9..d8f6496 100755 --- a/apol +++ b/apol @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. diff --git a/sediff b/sediff index 34268ca..48b1a54 100755 --- a/sediff +++ b/sediff @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. diff --git a/sedta b/sedta index e4d4914..279019c 100755 --- a/sedta +++ b/sedta @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. diff --git a/seinfo b/seinfo index 2b50393..ad83496 100755 --- a/seinfo +++ b/seinfo @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. diff --git a/seinfoflow b/seinfoflow index 7a2d288..1c75f8e 100755 --- a/seinfoflow +++ b/seinfoflow @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. diff --git a/sesearch b/sesearch index 7bcdfd2..e2cd4c3 100755 --- a/sesearch +++ b/sesearch @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. setools-4.1.1/patches/libsepol-2.4-mls-semantic-level-expand.patch000066400000000000000000000046771314142262400247600ustar00rootroot00000000000000This libsepol patch is needed if you see these unit test failures: ====================================================================== FAIL: test_306_level_lookup_cat_not_assoc (tests.policyrep.mls.LevelFactoryTest) Level lookup with category not associated with sensitivity. ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/pebenito/projects/setools/tests/policyrep/mls.py", line 121, in test_306_level_lookup_cat_not_assoc self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0,c4") AssertionError: InvalidLevel not raised by level_factory ====================================================================== FAIL: test_406_range_lookup_invalid_range_low (tests.policyrep.mls.RangeFactoryTest) Range lookup with an invalid range (low). ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/pebenito/projects/setools/tests/policyrep/mls.py", line 168, in test_406_range_lookup_invalid_range_low self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0:c13-s2:c13") AssertionError: InvalidRange not raised by range_factory ====================================================================== FAIL: test_407_range_lookup_invalid_range_high (tests.policyrep.mls.RangeFactoryTest) Range lookup with an invalid range (high). ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/pebenito/projects/setools/tests/policyrep/mls.py", line 173, in test_407_range_lookup_invalid_range_high self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0-s0:c13") AssertionError: InvalidRange not raised by range_factory ---------------------------------------------------------------------- diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index 467f7a7..3193ef5 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -914,10 +914,11 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, } for (i = cat->low - 1; i < cat->high; i++) { if (!ebitmap_get_bit(&levdatum->level->cat, i)) { - ERR(h, "Category %s can not be associate with " + ERR(h, "Category %s can not be associated with " "level %s", p->p_cat_val_to_name[i], p->p_sens_val_to_name[l->sens - 1]); + return -1; } if (ebitmap_set_bit(&l->cat, i, 1)) { ERR(h, "Out of memory!"); -- 2.3.0 setools-4.1.1/qhc/000077500000000000000000000000001314142262400137575ustar00rootroot00000000000000setools-4.1.1/qhc/analyses.html000066400000000000000000000004461314142262400164700ustar00rootroot00000000000000 Analyses

Analyses

Apol supports the following analyses:

setools-4.1.1/qhc/apol.qhcp000066400000000000000000000012611314142262400155670ustar00rootroot00000000000000 Apol Help qthelp://com.github.tresystechnology.setools/doc/index.html qthelp://com.github.tresystechnology.setools/doc/index.html apol.qhp apol.qch apol.qch setools-4.1.1/qhc/apol.qhp000066400000000000000000000026201314142262400154240ustar00rootroot00000000000000 com.github.tresystechnology.setools doc apol apol
*.html setools-4.1.1/qhc/components.html000066400000000000000000000007541314142262400170400ustar00rootroot00000000000000 Components

Components

The policy components tabs provide the means to examine, search, and relate the core components of an SELinux policy.

Apol supports querying the following policy components:

  • Booleans
  • Categories
  • Commons
  • Roles
  • Object Classes
  • Sensitivities
  • Types
  • Type Attributes
  • Users
setools-4.1.1/qhc/dta.html000066400000000000000000000140671314142262400154250ustar00rootroot00000000000000 Domain Transition Analysis

Domain Transition Analysis

A key feature of Type Enforcement (TE) security is the ability to define domain types with which programs run, use that domain type to control access to objects (which are also typed), and strictly control the ability of a process to change its domain type. This last ability is known as domain transition.

Apol supports analysis of an SELinux policy to understand the domain transitions it allows. As with all access in SELinux, the ability to transition from one domain to another is controlled by 'allow' rules in the policy. Below, we describe how apol performs a domain transition analysis.

Types Used in Domain Transitions

When discussing domain transition access, there are three different types we must consider:

  • SOURCE TYPE: This is the domain type associated with a process that is trying to change (transition) its domain type to another type.
  • TARGET TYPE: This is the domain type to which the source type is trying to transition.
  • FILE TYPE (ENTRYPOINT TYPE): This is a type associated with an executable file object that allows the target type to be entered as part of an exec() system call.

Domain Transition Criteria

In SELinux, there are two ways for a domain transition to occur, on exec(), and on setcon(). The common case is for a domain transition to occur on exec().

Transitions on Exec()

In SELinux, four types of access (and hence at four rules) must be allowed by the policy for a domain transition to occur. These access types form the criteria used by apol to determine allowed transitions.

The criteria for an allowed domain transition are as follows. In the examples below, assume user_t is the source type, passwd_t is the target type, and passwd_exec_t is the file entry point type.

  1. A rule must exist that allows the SOURCE domain type transition access for process object class for the TARGET domain type. For example, the rule:
    
        allow user_t passwd_t : process transition;
    
    
    meets this criterion by allowing the source type (user_t) process: transition permission to the target type (passwd_t).
  2. A rule must exist that allows the SOURCE domain type execute access to the FILE ENTRYPOINT type. For example, the rule:
    
        allow user_t passwd_exec_t : file { read getattr execute };
    
    
    meets the criterion by allowing the source type (user_t) execute access to the file entrypoint type (passwd_exec_t).
  3. A rule must exist that allows the TARGET domain type entrypoint access to the FILE ENTRYPOINT type for file objects. For example, the rule:
    
        allow passwd_t passwd_exec_t : file entrypoint;
    
    
    meets this criterion by allowing the target type (passwd_t) file: entrypoint access to the file entrypoint type (passwd_exec_t).
  4. There must be a way for the transition to be triggered. Typically this is accomplished in the policy with a TYPE TRANSITION statement. For example, the statement:
    
        type_transition user_t password_exec_t : process passwd_t;
    
    
    meets this criterion by specifying that when user_t executes a program with the passwd_exec_t type, the default type of the new process is passwd_t. This is the most common specifier because it does not require the programs to be SELinux-aware. Alternatively, the program can be made SELinux-aware and the program itself may specify the type of the new process. For example, the statement:
    
        allow user_t self : process setexec;
    
    
    allows the source type (user_t) to specify the type of new processes when executing programs. In both the type transition and setexec cases, the types that the source domain may transition to are limited by the previous three criterion.

In the analysis results, apol will list all the types that meet the above four criteria.

Transitions on Setcon()

SELinux also supports domain transitions that are requested by SELinux-aware programs (also known as a dynamic domain transition), using the setcon() libselinux function. Two types of access must be allowed by the policy for a dynamic domain transition to occur. These access types form the criteria used by apol to determine allowed transitions.

The criteria for an allowed dynamic domain transition are as follows. In the examples below, assume souce_t is the source type and, target_t is the target type.

  1. A rule must exist that allows the SOURCE domain type dyntransition access for process object class for the TARGET domain type. For example, the rule:
    
        allow source_t target_t : process transition;
    
    
    meets this criterion by allowing the source type (source_t) process: dyntransition permission to the target type (target_t).
  2. A rule must exist that allows the SOURCE domain type setcurrent access so it can set its current SELinux context. For example, the rule:
    
        allow source_t source_t : process setcurrent;
    
    
    meets the criterion by allowing the source type (source_t) setcurrent access on itself.

In the analysis results, apol will list all the types that meet the above two criteria.

Reverse Transitions

Apol supports both forward and reverse domain transition analysis. A forward analysis determines all the TARGET types to which the selected SOURCE types may transition (find child domains/processes). A reverse analysis is the opposite; select a TARGET type and determine all the SOURCE types that may transition to the target type (find parent domains/processes).

setools-4.1.1/qhc/index.html000066400000000000000000000035561314142262400157650ustar00rootroot00000000000000 Apol

Apol SELinux Policy Analysis

Overview

This file contains basic help information for using apol, a graphical policy analysis tool for Security Enhanced (SELinux) policies. The tool provides the ability to:

  1. Examine, search, and relate policy components (types, type attributes, object classes, object permissions, roles, users, initials SIDs, MLS components, network and file system contexts, and booleans), and policy rules.
  2. Perform some automated analysis of policies, including forward and reverse domain transition analyses, and information flow analysis.

Apol supports source, and binary policies. Certain apol features may be disabled if the underlying policy does not support the action. For example, rule searches will not report line numbers when searching monolithic binary polices.

Apol provides compatibility with the current and previous policy syntax. It supports analysis of policy versions 15 and up.

Menus

Use Open from the File menu to open a valid policy. Only one policy can be open at a time; opening a second policy will result in the first being closed.

The Permission Map menu allows for opening, editing, and saving permission mappings. These are used by apol's information flow analysis.

Starting an Analysis

To begin analyzing a policy, click the new analysis button. A menu of available analysis tools will be presented. Select one, and a new analysis tab will open. Any analysis can be started multiple times, and each will operate independently, so multiple concurrent analyses can be performed. To help manage multiple tabs, the tabs can be renamed by double-click the tab.

setools-4.1.1/qhc/infoflow.html000066400000000000000000000331751314142262400165010ustar00rootroot00000000000000 Information Flow Analysis

Information Flow Analysis

Apol supports the ability to automate the search for overt information flows between two types. The purpose of this analysis is to identify undesirable or unexpected flows of information allowed by a Type Enforcement (TE) policy. For example, imagine that the type shadow_t is assigned to the shadow password file /etc/shadow. To determine all the types to which information can flow from the shadow_t type (e.g, indicating possible paths for encrypted passwords to be unintentionally leaked), do a "flow from" analysis on the shadow_t type. Another example might be a firewall application where the intent is to understand all flows allowed between two network interfaces.

Information flow analysis in SELinux is challenging for several reasons, including:

  • The TE policy mechanism is extremely flexible, allowing for good and bad flows to be easily specified, not necessarily by the policy writer's intent.
  • TE policies tend to be complex, with possibly tens of thousands of rules and hundreds of types, making it difficult for a policy writer to know all that is allowed.
  • SELinux currently supports over 50 object classes and hundreds of object permissions, each of which must be examined with their ability to allow information flow from/to its associated object class.

The remainder of this file provides an overview on how apol performs information flow analysis.

What Is Overt Information Flow In SELinux?

Information flow is defined in terms of access allowed (not necessarily whether that access is actually used). In SELinux, all objects and subjects have an associated type. Generally speaking, subjects can read or write objects, and thereby cause information to flow into and out of objects, and into and out of themselves. For example, given two types (say subject_t and object_t) and a subject (with subject_t type) able to read, but not write, an object (with object_t type), a rule that would allow this access might look like the following:

allow subject_t object_t : {file link_file} read;

This case would have the following direct information flows for the types subject_t and object_t:

        subject_t: FROM object_t

        object_t:  TO subject_t

If this were the only rule relating to these two types, there would be no other direct information flows from or to either.

An information flow can only occur when a subject is involved; a flow directly between two objects cannot exist since a subject is required to cause action. In SELinux, processes are generally the subject. There are dozens of object classes (including processes, which are both subjects and objects).

In apol, the subject is easy to recognize; any type that is used in the 'source' field of an allow rule is presumed to be associated with a subject, usually as the domain type of some process. The object type is the type used in the 'target' field of an allow rule.

In the case of objects, the allow rule also explicitly identifies the object classes for which the rule applies. This fact results in a complication for analyzing information flows; specifically that flows between types are restricted by object classes. A flow between types is typically not allowed for all object classes, but for only those classes identified. So to be more precise, the direct information flows allowed by the object rules for object_t in the example above are:

        object_t [file, link_file]:  TO subject_t

A perspective difference exists between source (subject) types and target (object) types. A read permission between a source type and a target type is a flow out of the target (which is being read) and flow into the source (which, being a process, is receiving the data being read into its memory).

Object permission mappings

The above examples used 'read' permission, but described flows as 'in' or 'out' or 'from' and 'to'. In general, for information flow analysis, the only access between subjects and objects that are of interest, are read and write. Remembering the perspective difference mentioned above, read and write access results in the following flow for subjects (sources) and objects (targets):

        SUBJECT: READ:  IN flow
                 WRITE: OUT flow

        OBJECT:  READ:  OUT flow
                 WRITE: IN flow

NOTE: A process can be either a subject or an object, so when the process object class is specified in the allow rule, the target type is associated with process object class and the object flow rules apply.

Although read and write access are the only access rights of interest for an information flow analysis, 'read' and 'write' permissions are not the only SELinux permissions of interest. The name of a permission does not necessarily imply whether it allows read or write access. Indeed, to perform an information flow analysis requires mapping all defined permissions for all object classes to read and write access.

This mapping can be a difficult chore, and certainly requires extensive understanding of the access allowed by each of the hundreds of permissions currently defined. For example, the file object class has the getattr permission defined that allows the ability to determine information about a file (such as date created and size). One could consider this a read access since the subject is reading information about the file. Then again this begins to feel like COVERT information flow analysis, where one is concerned about illicit signaling of information through non-traditional means (e.g., signaling the critical data by varying the size of file is a covert flow, writing the data directly in the file so it can be read is an overt flow). This type of decision must be made for each defined object permission for each defined object class.

The permission mapping mechanism in apol allows each permission to be mapped to read, write, both or none. In addition, the tool attempts to 'fix' a permission map to fit the needs of the currently opened policy. So, for example, if a permission map file does not map a set of permissions, or skips an entire object class, apol will label the missing permissions to "unmapped" and treat them as if they were mapped to 'none.' Likewise, if a map has permissions that are undefined in the current policy, it will ignore those mappings.

Apol provides mechanisms to manage and customize permission mappings that best suit the analyst's needs. Use the Tools menu (see below) to modify permission mappings.

Permission Weighting

In addition to mapping each permission to read, write, both, or none, it is possible to assign the permission a weight between 1 and 10. Apol uses this weight to rate the importance of the information flow this permission represents and allows the user to make fine-grained distinctions between high-bandwidth, overt information flows and low-bandwidth, or difficult to exploit, covert information flows. For example, the permissions read and write on the file object could be given a weight of 10 because they are very high-bandwidth information flows. Additionally, the use permission on the fd object (file descriptor) would probably be given a weight of 1 as it is a very low-bandwidth covert flow at best. Note that a permission might be important for access control, like fd: use, but be given a low weight for information flow because it cannot be used to pass large amounts of information.

The default permission maps that are installed with apol have weights assigned for all of the permissions. The weights are in four general categories as follows:

  • 1 - 2 difficult to exploit covert flows (example: fd:use)
  • 3 - 5 less difficult to exploit covert flows (example: process:signal)
  • 6 - 7 difficult to use, noisy, or low-bandwidth overt flows (example: file:setattr)
  • 8 - 10 high-bandwidth overt flows (example: file:write)

These categories are loosely defined and the placement of permissions into these categories is subjective. Additional work needs to be done to verify the accuracy of both the mappings of the permissions and the assigned weights.

Types of information flow analysis

The examples so far have only looked at 'direct' information flows. As its name implies, direct information flow analysis examines a policy for information flows that are directly permitted by one or more allow rules. In essence, every allow rule defines a direct information flow between the source and target types (for those allowed permissions that map to read, write, or both). The direct information flow analysis automates the search for these direct flows.

Transitive information flow analysis attempts to link together a series of direct information flows to find an indirect path in which information can flow between two types. The results for a transitive closure will show one or more steps in the chain required for information to flow between the start and end types. Currently, the results will only show one such path for each end type; specifically the shortest path.

For example, given the following rules:

        allow one_t two_t : file write;
        allow three_t two_t: file read;

A direct flow analysis between one_t and three_t would not show any flows since no rule explicitly allows access between them. However, a two-step flow exists that would allow flow between these two types, namely one_t writing information into a file type (two_t) that three_t can read. These are the types of flows that the transitive analysis attempts to find.

For direct analyses, the results are presented in tree form in the browser tab. Each node in the tree represents a flow (in the direction selected) between the type of the parent node and the type of the node. The results window shows each step of the flow including the contributing access rule(s).

Managing Permission Mappings

The ability to directly manage permission maps is important for the following reasons:

  • Permission maps are central to analyzing information flows, and the correctness of the map has a direct influence on the value of he results.
  • The mapping for individual permissions and object classes are subjective, and changing permissions to alter the analysis might be necessary (e.g., by unmapping certain object classes to remove them from the analysis).
  • The analyst may be working with several different policies each with different definitions of object classes and permissions.

Because of these reasons, apol was designed to provide great latitude in managing permission mappings using Permission Map menu. A user need not manage permission maps directly; apol is installed with default permission maps (typically in /usr/share/setools/perm_map) that will be loaded automatically when an information flow analysis is performed.

Use the Permission Map menu to manually load a permission map from an arbitrary file. This capability allows the user to keep several versions of permission map files, loading the correct one for a given analysis.

Although the user could view and modify mappings by editing a map file directly, an easier (and less error-prone) approach is apol's perm map viewer. Select Edit Permission Mapfrom the Permission Map menu to display all object classes and permissions currently mapped (or unmapped) in the currently loaded policy. In addition, each permission's weight value is shown. These values tell apol the importance of each permission to the analysis. The user can configure these weight values according to the analysis goals. For example, the user may consider any read or write permissions of highest importance to the analysis, whereas permission to use a file descriptor may be of least importance. A permission will default to a weight of 1 if a weight value is not provided for the permission in the permission map.

Finding more flows

For a transitive information flow, there might be many different information flows between two types. For example, given the following policy:

        allow one_t two_t : file write;
        allow three_t two_t: file read;
        allow four_t two_t: file read;
        allow four_t three_t: file write;

In this policy, two ways exist that information can flow between one_t and three_t: through three_t and through three_t and four_t. In complicated policies, many information flows between two types can exist. The analysis algorithm can find all information flows, but this would be time prohibitive on large policies. Apol provides two ways of constraining the analysis time. Two analysis algorithms are provided:

  1. Shortest Paths: The shortest path between the source and target type will be found. If there are multiple shortest paths, all with be found.
  2. All Paths: All paths between the source and target type will be found. To constrain this, an upper limit of path length must be specified. For typical policies, a path length more than 4 or 5 may be very expensive.

Additionally, the analysis can be constrained by number of results. The Limit Results option will stop the analysis if the specified number of results is reached. There is no idication if there are more results

setools-4.1.1/qhc/labeling.html000066400000000000000000000005571314142262400164310ustar00rootroot00000000000000 Labeling

Labeling

Apol supports querying the following labeling statements:

  • Fs_use_* Statements
  • Genfscon Statements
  • Initial SID Statements
  • Netifcon Statements
  • Nodecon Statements
  • Portcon Statements
setools-4.1.1/qhc/rules.html000066400000000000000000000004631314142262400160020ustar00rootroot00000000000000 Rules

Rules

Apol supports querying the following rule types:

  • Constraints
  • Multi-level Security (MLS)
  • Role-based Access Control (RBAC)
  • Type Enforcement (TE)
setools-4.1.1/sediff000077500000000000000000002253171314142262400144040ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import setools import argparse import sys import logging from itertools import chain parser = argparse.ArgumentParser( description="SELinux policy semantic difference tool.", epilog="If no differences are selected, all differences will be printed.") parser.add_argument("POLICY1", help="Path to the first SELinux policy to diff.", nargs=1) parser.add_argument("POLICY2", help="Path to the second SELinux policy to diff.", nargs=1) parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("--stats", action="store_true", help="Display only statistics.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") comp = parser.add_argument_group("component differences") comp.add_argument("--common", action="store_true", help="Print common differences") comp.add_argument("-c", "--class", action="store_true", help="Print class differences", dest="class_") comp.add_argument("-t", "--type", action="store_true", help="Print type differences", dest="type_") comp.add_argument("-a", "--attribute", action="store_true", help="Print type attribute differences") comp.add_argument("-r", "--role", action="store_true", help="Print role differences") comp.add_argument("-u", "--user", action="store_true", help="Print user differences") comp.add_argument("-b", "--bool", action="store_true", help="Print Boolean differences", dest="bool_") comp.add_argument("--sensitivity", action="store_true", help="Print MLS sensitivity differences") comp.add_argument("--category", action="store_true", help="Print MLS category differences") comp.add_argument("--level", action="store_true", help="Print MLS level definition differences") terule = parser.add_argument_group("type enforcement rule differences") terule.add_argument("-A", action="store_true", help="Print allow and allowxperm rule differences") terule.add_argument("--allow", action="store_true", help="Print allow rule differences") terule.add_argument("--neverallow", action="store_true", help="Print neverallow rule differences") terule.add_argument("--auditallow", action="store_true", help="Print auditallow rule differences") terule.add_argument("--dontaudit", action="store_true", help="Print dontaudit rule differences") terule.add_argument("--allowxperm", action="store_true", help="Print allowxperm rule differences") terule.add_argument("--neverallowxperm", action="store_true", help="Print neverallowxperm rule differences") terule.add_argument("--auditallowxperm", action="store_true", help="Print auditallowxperm rule differences") terule.add_argument("--dontauditxperm", action="store_true", help="Print dontauditxperm rule differences") terule.add_argument("-T", "--type_trans", action="store_true", help="Print type_transition rule differences") terule.add_argument("--type_change", action="store_true", help="Print type_change rule differences") terule.add_argument("--type_member", action="store_true", help="Print type_member rule differences") rbacrule = parser.add_argument_group("RBAC rule differences") rbacrule.add_argument("--role_allow", action="store_true", help="Print role allow rule differences") rbacrule.add_argument("--role_trans", action="store_true", help="Print role_transition rule differences") mlsrule = parser.add_argument_group("MLS rule differences") mlsrule.add_argument("--range_trans", action="store_true", help="Print range_transition rule differences") constrain = parser.add_argument_group("Constraint differences") constrain.add_argument("--constrain", action="store_true", help="Print constrain differences") constrain.add_argument("--mlsconstrain", action="store_true", help="Print mlsconstrain differences") constrain.add_argument("--validatetrans", action="store_true", help="Print validatetrans differences") constrain.add_argument("--mlsvalidatetrans", action="store_true", help="Print mlsvalidatetrans differences") labeling = parser.add_argument_group("labeling statement differences") labeling.add_argument("--initialsid", action="store_true", help="Print initial SID differences") labeling.add_argument("--fs_use", action="store_true", help="Print fs_use_* differences") labeling.add_argument("--genfscon", action="store_true", help="Print genfscon differences") labeling.add_argument("--netifcon", action="store_true", help="Print netifcon differences") labeling.add_argument("--nodecon", action="store_true", help="Print nodecon differences") labeling.add_argument("--portcon", action="store_true", help="Print portcon differences") other = parser.add_argument_group("other differences") other.add_argument("--default", action="store_true", help="Print default_* differences") other.add_argument("--property", action="store_true", help="Print policy property differences (handle_unknown, version, MLS)") other.add_argument("--polcap", action="store_true", help="Print policy capability differences") other.add_argument("--typebounds", action="store_true", help="Print typebounds differences") args = parser.parse_args() if args.A: args.allow = True args.allowxperm = True all_differences = not any((args.class_, args.common, args.type_, args.attribute, args.role, args.user, args.bool_, args.sensitivity, args.category, args.level, args.allow, args.neverallow, args.auditallow, args.dontaudit, args.type_trans, args.type_change, args.type_member, args.role_allow, args.role_trans, args.range_trans, args.initialsid, args.genfscon, args.netifcon, args.nodecon, args.portcon, args.fs_use, args.polcap, args.property, args.default, args.constrain, args.mlsconstrain, args.validatetrans, args.mlsvalidatetrans, args.typebounds, args.allowxperm, args.neverallowxperm, args.auditallowxperm, args.dontauditxperm)) if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p1 = setools.SELinuxPolicy(args.POLICY1[0]) p2 = setools.SELinuxPolicy(args.POLICY2[0]) diff = setools.PolicyDifference(p1, p2) if all_differences or args.property: print("Policy Properties ({0} Modified)".format(len(diff.modified_properties))) if diff.modified_properties and not args.stats: for name, added, removed in sorted(diff.modified_properties, key=lambda x: x.property): print(" * {0} +{1} -{2}".format(name, added, removed)) print() del diff.modified_properties if all_differences or args.common: if diff.added_commons or diff.removed_commons or diff.modified_commons or args.common: print("Commons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_commons), len(diff.removed_commons), len(diff.modified_commons))) if diff.added_commons and not args.stats: print(" Added Commons: {0}".format(len(diff.added_commons))) for c in sorted(diff.added_commons): print(" + {0}".format(c)) if diff.removed_commons and not args.stats: print(" Removed Commons: {0}".format(len(diff.removed_commons))) for c in sorted(diff.removed_commons): print(" - {0}".format(c)) if diff.modified_commons and not args.stats: print(" Modified Commons: {0}".format(len(diff.modified_commons))) for name, mod in sorted(diff.modified_commons.items()): change = [] if mod.added_perms: change.append("{0} Added permissions".format(len(mod.added_perms))) if mod.removed_perms: change.append("{0} Removed permissions".format(len(mod.removed_perms))) print(" * {0} ({1})".format(name, ", ".join(change))) for p in sorted(mod.added_perms): print(" + {0}".format(p)) for p in sorted(mod.removed_perms): print(" - {0}".format(p)) print() del diff.added_commons del diff.removed_commons del diff.modified_commons if all_differences or args.class_: if diff.added_classes or diff.removed_classes or diff.modified_classes or args.class_: print("Classes ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_classes), len(diff.removed_classes), len(diff.modified_classes))) if diff.added_classes and not args.stats: print(" Added Classes: {0}".format(len(diff.added_classes))) for c in sorted(diff.added_classes): print(" + {0}".format(c)) if diff.removed_classes and not args.stats: print(" Removed Classes: {0}".format(len(diff.removed_classes))) for c in sorted(diff.removed_classes): print(" - {0}".format(c)) if diff.modified_classes and not args.stats: print(" Modified Classes: {0}".format(len(diff.modified_classes))) for name, mod in sorted(diff.modified_classes.items()): change = [] if mod.added_perms: change.append("{0} Added permissions".format(len(mod.added_perms))) if mod.removed_perms: change.append("{0} Removed permissions".format(len(mod.removed_perms))) print(" * {0} ({1})".format(name, ", ".join(change))) for p in sorted(mod.added_perms): print(" + {0}".format(p)) for p in sorted(mod.removed_perms): print(" - {0}".format(p)) print() del diff.added_classes del diff.removed_classes del diff.modified_classes if all_differences or args.bool_: if diff.added_booleans or diff.removed_booleans or \ diff.modified_booleans or args.bool_: print("Booleans ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_booleans), len(diff.removed_booleans), len(diff.modified_booleans))) if diff.added_booleans and not args.stats: print(" Added Booleans: {0}".format(len(diff.added_booleans))) for a in sorted(diff.added_booleans): print(" + {0}".format(a)) if diff.removed_booleans and not args.stats: print(" Removed Booleans: {0}".format(len(diff.removed_booleans))) for a in sorted(diff.removed_booleans): print(" - {0}".format(a)) if diff.modified_booleans and not args.stats: print(" Modified Booleans: {0}".format(len(diff.modified_booleans))) for name, mod in sorted(diff.modified_booleans.items()): print(" * {0} (Modified default state)".format(name)) print(" + {0}".format(mod.added_state)) print(" - {0}".format(mod.removed_state)) print() del diff.added_booleans del diff.removed_booleans del diff.modified_booleans if all_differences or args.role: if diff.added_roles or diff.removed_roles or diff.modified_roles or args.role: print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles), len(diff.removed_roles), len(diff.modified_roles))) if diff.added_roles and not args.stats: print(" Added Roles: {0}".format(len(diff.added_roles))) for r in sorted(diff.added_roles): print(" + {0}".format(r)) if diff.removed_roles and not args.stats: print(" Removed Roles: {0}".format(len(diff.removed_roles))) for r in sorted(diff.removed_roles): print(" - {0}".format(r)) if diff.modified_roles and not args.stats: print(" Modified Roles: {0}".format(len(diff.modified_roles))) for name, mod in sorted(diff.modified_roles.items()): change = [] if mod.added_types: change.append("{0} Added types".format(len(mod.added_types))) if mod.removed_types: change.append("{0} Removed types".format(len(mod.removed_types))) print(" * {0} ({1})".format(name, ", ".join(change))) for t in sorted(mod.added_types): print(" + {0}".format(t)) for t in sorted(mod.removed_types): print(" - {0}".format(t)) print() del diff.added_roles del diff.removed_roles del diff.modified_roles if all_differences or args.type_: if diff.added_types or diff.removed_types or diff.modified_types or args.type_: print("Types ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_types), len(diff.removed_types), len(diff.modified_types))) if diff.added_types and not args.stats: print(" Added Types: {0}".format(len(diff.added_types))) for r in sorted(diff.added_types): print(" + {0}".format(r)) if diff.removed_types and not args.stats: print(" Removed Types: {0}".format(len(diff.removed_types))) for r in sorted(diff.removed_types): print(" - {0}".format(r)) if diff.modified_types and not args.stats: print(" Modified Types: {0}".format(len(diff.modified_types))) for name, mod in sorted(diff.modified_types.items()): change = [] if mod.added_attributes: change.append("{0} Added attributes".format(len(mod.added_attributes))) if mod.removed_attributes: change.append("{0} Removed attributes".format(len(mod.removed_attributes))) if mod.added_aliases: change.append("{0} Added aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed aliases".format(len(mod.removed_aliases))) if mod.modified_permissive: if mod.permissive: change.append("Removed permissive") else: change.append("Added permissive") print(" * {0} ({1})".format(name, ", ".join(change))) if mod.added_attributes or mod.removed_attributes: print(" Attributes:") for t in sorted(mod.added_attributes): print(" + {0}".format(t)) for t in sorted(mod.removed_attributes): print(" - {0}".format(t)) if mod.added_aliases or mod.removed_aliases: print(" Aliases:") for t in sorted(mod.added_aliases): print(" + {0}".format(t)) for t in sorted(mod.removed_aliases): print(" - {0}".format(t)) print() del diff.added_types del diff.removed_types del diff.modified_types if all_differences or args.attribute: if diff.added_type_attributes or diff.removed_type_attributes or \ diff.modified_type_attributes or args.attribute: print("Type Attributes ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_attributes), len(diff.removed_type_attributes), len(diff.modified_type_attributes))) if diff.added_type_attributes and not args.stats: print(" Added Type Attributes: {0}".format(len(diff.added_type_attributes))) for a in sorted(diff.added_type_attributes): print(" + {0}".format(a)) if diff.removed_type_attributes and not args.stats: print(" Removed Type Attributes: {0}".format(len(diff.removed_type_attributes))) for a in sorted(diff.removed_type_attributes): print(" - {0}".format(a)) if diff.modified_type_attributes and not args.stats: print(" Modified Type Attributes: {0}".format(len(diff.modified_type_attributes))) for name, mod in sorted(diff.modified_type_attributes.items()): change = [] if mod.added_types: change.append("{0} Added types".format(len(mod.added_types))) if mod.removed_types: change.append("{0} Removed types".format(len(mod.removed_types))) print(" * {0} ({1})".format(name, ", ".join(change))) for t in sorted(mod.added_types): print(" + {0}".format(t)) for t in sorted(mod.removed_types): print(" - {0}".format(t)) print() del diff.added_type_attributes del diff.removed_type_attributes del diff.modified_type_attributes if all_differences or args.user: if diff.added_users or diff.removed_users or diff.modified_users or args.user: print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users), len(diff.removed_users), len(diff.modified_users))) if diff.added_users and not args.stats: print(" Added Users: {0}".format(len(diff.added_users))) for u in sorted(diff.added_users): print(" + {0}".format(u)) if diff.removed_users and not args.stats: print(" Removed Users: {0}".format(len(diff.removed_users))) for u in sorted(diff.removed_users): print(" - {0}".format(u)) if diff.modified_users and not args.stats: print(" Modified Users: {0}".format(len(diff.modified_users))) for name, mod in sorted(diff.modified_users.items()): change = [] if mod.added_roles: change.append("{0} Added roles".format(len(mod.added_roles))) if mod.removed_roles: change.append("{0} Removed roles".format(len(mod.removed_roles))) if mod.removed_level: change.append("Modified default level") if mod.removed_range: change.append("Modified range") print(" * {0} ({1})".format(name, ", ".join(change))) if mod.added_roles or mod.removed_roles: print(" Roles:") for t in sorted(mod.added_roles): print(" + {0}".format(t)) for t in sorted(mod.removed_roles): print(" - {0}".format(t)) if mod.removed_level: print(" Default level:") print(" + {0}".format(mod.added_level)) print(" - {0}".format(mod.removed_level)) if mod.removed_range: print(" Range:") print(" + {0}".format(mod.added_range)) print(" - {0}".format(mod.removed_range)) print() del diff.added_users del diff.removed_users del diff.modified_users if all_differences or args.category: if diff.added_categories or diff.removed_categories or diff.modified_categories \ or args.category: print("Categories ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_categories), len(diff.removed_categories), len(diff.modified_categories))) if diff.added_categories and not args.stats: print(" Added Categories: {0}".format(len(diff.added_categories))) for c in sorted(diff.added_categories): print(" + {0}".format(c)) if diff.removed_categories and not args.stats: print(" Removed Categories: {0}".format(len(diff.removed_categories))) for c in sorted(diff.removed_categories): print(" - {0}".format(c)) if diff.modified_categories and not args.stats: print(" Modified Categories: {0}".format(len(diff.modified_categories))) for name, mod in sorted(diff.modified_categories.items()): change = [] if mod.added_aliases: change.append("{0} Added Aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) print(" * {0} ({1})".format(name, ", ".join(change))) print(" Aliases:") for a in sorted(mod.added_aliases): print(" + {0}".format(a)) for a in sorted(mod.removed_aliases): print(" - {0}".format(a)) print() del diff.added_categories del diff.removed_categories del diff.modified_categories if all_differences or args.sensitivity: if diff.added_sensitivities or diff.removed_sensitivities or diff.modified_sensitivities \ or args.sensitivity: print("Sensitivities ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_sensitivities), len(diff.removed_sensitivities), len(diff.modified_sensitivities))) if diff.added_sensitivities and not args.stats: print(" Added Sensitivites: {0}".format(len(diff.added_sensitivities))) for s in sorted(diff.added_sensitivities): print(" + {0}".format(s)) if diff.removed_sensitivities and not args.stats: print(" Removed Sensitivities: {0}".format(len(diff.removed_sensitivities))) for s in sorted(diff.removed_sensitivities): print(" - {0}".format(s)) if diff.modified_sensitivities and not args.stats: print(" Modified Sensitivities: {0}".format(len(diff.modified_sensitivities))) for name, mod in sorted(diff.modified_sensitivities.items()): change = [] if mod.added_aliases: change.append("{0} Added Aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) print(" * {0} ({1})".format(name, ", ".join(change))) print(" Aliases:") for a in sorted(mod.added_aliases): print(" + {0}".format(a)) for a in sorted(mod.removed_aliases): print(" - {0}".format(a)) print() del diff.added_sensitivities del diff.removed_sensitivities del diff.modified_sensitivities if all_differences or args.level: if diff.added_levels or diff.removed_levels or \ diff.modified_levels or args.level: print("Levels ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_levels), len(diff.removed_levels), len(diff.modified_levels))) if diff.added_levels and not args.stats: print(" Added Levels: {0}".format(len(diff.added_levels))) for l in sorted(diff.added_levels): print(" + {0}".format(l)) if diff.removed_levels and not args.stats: print(" Removed Levels: {0}".format(len(diff.removed_levels))) for l in sorted(diff.removed_levels): print(" - {0}".format(l)) if diff.modified_levels and not args.stats: print(" Modified Levels: {0}".format(len(diff.modified_levels))) for level, added_categories, removed_categories, _ in sorted(diff.modified_levels, key=lambda x: x.level): change = [] if added_categories: change.append("{0} Added Categories".format(len(added_categories))) if removed_categories: change.append("{0} Removed Categories".format(len(removed_categories))) print(" * {0} ({1})".format(level.sensitivity, ", ".join(change))) for c in sorted(added_categories): print(" + {0}".format(c)) for c in sorted(removed_categories): print(" - {0}".format(c)) print() del diff.added_levels del diff.removed_levels del diff.modified_levels if all_differences or args.allow: if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow: print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_allows), len(diff.removed_allows), len(diff.modified_allows))) if diff.added_allows and not args.stats: print(" Added Allow Rules: {0}".format(len(diff.added_allows))) for r in sorted(diff.added_allows): print(" + {0}".format(r)) if diff.removed_allows and not args.stats: print(" Removed Allow Rules: {0}".format(len(diff.removed_allows))) for r in sorted(diff.removed_allows): print(" - {0}".format(r)) if diff.modified_allows and not args.stats: print(" Modified Allow Rules: {0}".format(len(diff.modified_allows))) for rule, added_perms, removed_perms, matched_perms in sorted(diff.modified_allows, key=lambda x: x.rule): perms = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perms) try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_allows del diff.removed_allows del diff.modified_allows if all_differences or args.allowxperm: if diff.added_allowxperms or diff.removed_allowxperms or diff.modified_allowxperms \ or args.allowxperm: print("Allowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_allowxperms), len(diff.removed_allowxperms), len(diff.modified_allowxperms))) if diff.added_allowxperms and not args.stats: print(" Added Allowxperm Rules: {0}".format(len(diff.added_allowxperms))) for r in sorted(diff.added_allowxperms): print(" + {0}".format(r)) if diff.removed_allowxperms and not args.stats: print(" Removed Allowxperm Rules: {0}".format(len(diff.removed_allowxperms))) for r in sorted(diff.removed_allowxperms): print(" - {0}".format(r)) if diff.modified_allowxperms and not args.stats: print(" Modified Allowxperm Rules: {0}".format(len(diff.modified_allowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_allowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_allowxperms del diff.removed_allowxperms del diff.modified_allowxperms if all_differences or args.neverallow: if diff.added_neverallows or diff.removed_neverallows or diff.modified_neverallows or \ args.neverallow: print("Neverallow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_neverallows), len(diff.removed_neverallows), len(diff.modified_neverallows))) if diff.added_neverallows and not args.stats: print(" Added Neverallow Rules: {0}".format(len(diff.added_neverallows))) for r in sorted(diff.added_neverallows): print(" + {0}".format(r)) if diff.removed_neverallows and not args.stats: print(" Removed Neverallow Rules: {0}".format(len(diff.removed_neverallows))) for r in sorted(diff.removed_neverallows): print(" - {0}".format(r)) if diff.modified_neverallows and not args.stats: print(" Modified Neverallow Rules: {0}".format(len(diff.modified_neverallows))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_neverallows, key=lambda x: x.rule): perms = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perms) try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_neverallows del diff.removed_neverallows del diff.modified_neverallows if all_differences or args.neverallowxperm: if diff.added_neverallowxperms or diff.removed_neverallowxperms or \ diff.modified_neverallowxperms or args.neverallowxperm: print("Neverallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_neverallowxperms), len(diff.removed_neverallowxperms), len(diff.modified_neverallowxperms))) if diff.added_neverallowxperms and not args.stats: print(" Added Neverallowxperm Rules: {0}".format( len(diff.added_neverallowxperms))) for r in sorted(diff.added_neverallowxperms): print(" + {0}".format(r)) if diff.removed_neverallowxperms and not args.stats: print(" Removed Neverallowxperm Rules: {0}".format( len(diff.removed_neverallowxperms))) for r in sorted(diff.removed_neverallowxperms): print(" - {0}".format(r)) if diff.modified_neverallowxperms and not args.stats: print(" Modified Neverallowxperm Rules: {0}".format( len(diff.modified_neverallowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_neverallowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_neverallowxperms del diff.removed_neverallowxperms del diff.modified_neverallowxperms if all_differences or args.auditallow: if diff.added_auditallows or diff.removed_auditallows or diff.modified_auditallows or \ args.auditallow: print("Auditallow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_auditallows), len(diff.removed_auditallows), len(diff.modified_auditallows))) if diff.added_auditallows and not args.stats: print(" Added Auditallow Rules: {0}".format(len(diff.added_auditallows))) for r in sorted(diff.added_auditallows): print(" + {0}".format(r)) if diff.removed_auditallows and not args.stats: print(" Removed Auditallow Rules: {0}".format(len(diff.removed_auditallows))) for r in sorted(diff.removed_auditallows): print(" - {0}".format(r)) if diff.modified_auditallows and not args.stats: print(" Modified Auditallow Rules: {0}".format(len(diff.modified_auditallows))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_auditallows, key=lambda x: x.rule): perms = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perms) try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_auditallows del diff.removed_auditallows del diff.modified_auditallows if all_differences or args.auditallowxperm: if diff.added_auditallowxperms or diff.removed_auditallowxperms or \ diff.modified_auditallowxperms or args.auditallowxperm: print("Auditallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_auditallowxperms), len(diff.removed_auditallowxperms), len(diff.modified_auditallowxperms))) if diff.added_auditallowxperms and not args.stats: print(" Added Auditallowxperm Rules: {0}".format( len(diff.added_auditallowxperms))) for r in sorted(diff.added_auditallowxperms): print(" + {0}".format(r)) if diff.removed_auditallowxperms and not args.stats: print(" Removed Auditallowxperm Rules: {0}".format( len(diff.removed_auditallowxperms))) for r in sorted(diff.removed_auditallowxperms): print(" - {0}".format(r)) if diff.modified_auditallowxperms and not args.stats: print(" Modified Auditallowxperm Rules: {0}".format( len(diff.modified_auditallowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_auditallowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_auditallowxperms del diff.removed_auditallowxperms del diff.modified_auditallowxperms if all_differences or args.dontaudit: if diff.added_dontaudits or diff.removed_dontaudits or diff.modified_dontaudits or \ args.dontaudit: print("Dontaudit Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_dontaudits), len(diff.removed_dontaudits), len(diff.modified_dontaudits))) if diff.added_dontaudits and not args.stats: print(" Added Dontaudit Rules: {0}".format(len(diff.added_dontaudits))) for r in sorted(diff.added_dontaudits): print(" + {0}".format(r)) if diff.removed_dontaudits and not args.stats: print(" Removed Dontaudit Rules: {0}".format(len(diff.removed_dontaudits))) for r in sorted(diff.removed_dontaudits): print(" - {0}".format(r)) if diff.modified_dontaudits and not args.stats: print(" Modified Dontaudit Rules: {0}".format(len(diff.modified_dontaudits))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_dontaudits, key=lambda x: x.rule): perms = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perms) try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_dontaudits del diff.removed_dontaudits del diff.modified_dontaudits if all_differences or args.dontauditxperm: if diff.added_dontauditxperms or diff.removed_dontauditxperms or \ diff.modified_dontauditxperms or args.dontauditxperm: print("Dontauditxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_dontauditxperms), len(diff.removed_dontauditxperms), len(diff.modified_dontauditxperms))) if diff.added_dontauditxperms and not args.stats: print(" Added Dontauditxperm Rules: {0}".format( len(diff.added_dontauditxperms))) for r in sorted(diff.added_dontauditxperms): print(" + {0}".format(r)) if diff.removed_dontauditxperms and not args.stats: print(" Removed Dontauditxperm Rules: {0}".format( len(diff.removed_dontauditxperms))) for r in sorted(diff.removed_dontauditxperms): print(" - {0}".format(r)) if diff.modified_dontauditxperms and not args.stats: print(" Modified Dontauditxperm Rules: {0}".format( len(diff.modified_dontauditxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_dontauditxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_dontauditxperms del diff.removed_dontauditxperms del diff.modified_dontauditxperms if all_differences or args.type_trans: if diff.added_type_transitions or diff.removed_type_transitions or \ diff.modified_type_transitions or args.type_trans: print("Type_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_transitions), len(diff.removed_type_transitions), len(diff.modified_type_transitions))) if diff.added_type_transitions and not args.stats: print(" Added Type_transition Rules: {0}".format( len(diff.added_type_transitions))) for r in sorted(diff.added_type_transitions): print(" + {0}".format(r)) if diff.removed_type_transitions and not args.stats: print(" Removed Type_transition Rules: {0}".format( len(diff.removed_type_transitions))) for r in sorted(diff.removed_type_transitions): print(" - {0}".format(r)) if diff.modified_type_transitions and not args.stats: print(" Modified Type_transition Rules: {0}".format( len(diff.modified_type_transitions))) for rule, added_default, removed_default in sorted(diff.modified_type_transitions, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) try: rule_string += " {0}".format(rule.filename) except AttributeError: pass rule_string += ";" try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_type_transitions del diff.removed_type_transitions del diff.modified_type_transitions if all_differences or args.type_change: if diff.added_type_changes or diff.removed_type_changes or \ diff.modified_type_changes or args.type_change: print("Type_change Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_changes), len(diff.removed_type_changes), len(diff.modified_type_changes))) if diff.added_type_changes and not args.stats: print(" Added Type_change Rules: {0}".format(len(diff.added_type_changes))) for r in sorted(diff.added_type_changes): print(" + {0}".format(r)) if diff.removed_type_changes and not args.stats: print(" Removed Type_change Rules: {0}".format(len(diff.removed_type_changes))) for r in sorted(diff.removed_type_changes): print(" - {0}".format(r)) if diff.modified_type_changes and not args.stats: print(" Modified Type_change Rules: {0}".format(len(diff.modified_type_changes))) for rule, added_default, removed_default in sorted(diff.modified_type_changes, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) try: rule_string += " {0}".format(rule.filename) except AttributeError: pass rule_string += ";" try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_type_changes del diff.removed_type_changes del diff.modified_type_changes if all_differences or args.type_member: if diff.added_type_members or diff.removed_type_members or \ diff.modified_type_members or args.type_member: print("Type_member Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_members), len(diff.removed_type_members), len(diff.modified_type_members))) if diff.added_type_members and not args.stats: print(" Added Type_member Rules: {0}".format(len(diff.added_type_members))) for r in sorted(diff.added_type_members): print(" + {0}".format(r)) if diff.removed_type_members and not args.stats: print(" Removed Type_member Rules: {0}".format(len(diff.removed_type_members))) for r in sorted(diff.removed_type_members): print(" - {0}".format(r)) if diff.modified_type_members and not args.stats: print(" Modified Type_member Rules: {0}".format(len(diff.modified_type_members))) for rule, added_default, removed_default in sorted(diff.modified_type_members, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) try: rule_string += " {0}".format(rule.filename) except AttributeError: pass rule_string += ";" try: rule_string += " [ {0} ]".format(rule.conditional) except AttributeError: pass print(" * {0}".format(rule_string)) print() del diff.added_type_members del diff.removed_type_members del diff.modified_type_members if all_differences or args.role_allow: if diff.added_role_allows or diff.removed_role_allows or args.role_allow: print("Role allow Rules ({0} Added, {1} Removed)".format( len(diff.added_role_allows), len(diff.removed_role_allows))) if diff.added_role_allows and not args.stats: print(" Added Role Allow Rules: {0}".format( len(diff.added_role_allows))) for r in sorted(diff.added_role_allows): print(" + {0}".format(r)) if diff.removed_role_allows and not args.stats: print(" Removed Role Allow Rules: {0}".format( len(diff.removed_role_allows))) for r in sorted(diff.removed_role_allows): print(" - {0}".format(r)) print() del diff.added_role_allows del diff.removed_role_allows if all_differences or args.role_trans: if diff.added_role_transitions or diff.removed_role_transitions or \ diff.modified_role_transitions or args.role_trans: print("Role_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_role_transitions), len(diff.removed_role_transitions), len(diff.modified_role_transitions))) if diff.added_role_transitions and not args.stats: print(" Added Role_transition Rules: {0}".format( len(diff.added_role_transitions))) for r in sorted(diff.added_role_transitions): print(" + {0}".format(r)) if diff.removed_role_transitions and not args.stats: print(" Removed Role_transition Rules: {0}".format( len(diff.removed_role_transitions))) for r in sorted(diff.removed_role_transitions): print(" - {0}".format(r)) if diff.modified_role_transitions and not args.stats: print(" Modified Role_transition Rules: {0}".format( len(diff.modified_role_transitions))) for rule, added_default, removed_default in sorted(diff.modified_role_transitions, key=lambda x: x.rule): rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) print(" * {0}".format(rule_string)) print() del diff.added_role_transitions del diff.removed_role_transitions del diff.modified_role_transitions if all_differences or args.range_trans: if diff.added_range_transitions or diff.removed_range_transitions or \ diff.modified_range_transitions or args.range_trans: print("Range_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_range_transitions), len(diff.removed_range_transitions), len(diff.modified_range_transitions))) if diff.added_range_transitions and not args.stats: print(" Added Range_transition Rules: {0}".format( len(diff.added_range_transitions))) for r in sorted(diff.added_range_transitions): print(" + {0}".format(r)) if diff.removed_range_transitions and not args.stats: print(" Removed Range_transition Rules: {0}".format( len(diff.removed_range_transitions))) for r in sorted(diff.removed_range_transitions): print(" - {0}".format(r)) if diff.modified_range_transitions and not args.stats: print(" Modified Range_transition Rules: {0}".format( len(diff.modified_range_transitions))) for rule, added_default, removed_default in sorted(diff.modified_range_transitions, key=lambda x: x.rule): # added brackets around range change for clarity since ranges # can have '-' and spaces. rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} +[{1}] -[{2}]".format( rule, added_default, removed_default) print(" * {0}".format(rule_string)) print() del diff.added_range_transitions del diff.removed_range_transitions del diff.modified_range_transitions if all_differences or args.constrain: if diff.added_constrains or diff.removed_constrains or args.constrain: print("Constraints ({0} Added, {1} Removed)".format( len(diff.added_constrains), len(diff.removed_constrains))) if diff.added_constrains and not args.stats: print(" Added Constraints: {0}".format( len(diff.added_constrains))) for r in sorted(diff.added_constrains): print(" + {0}".format(r)) if diff.removed_constrains and not args.stats: print(" Removed Constraints: {0}".format( len(diff.removed_constrains))) for r in sorted(diff.removed_constrains): print(" - {0}".format(r)) print() del diff.added_constrains del diff.removed_constrains if all_differences or args.mlsconstrain: if diff.added_mlsconstrains or diff.removed_mlsconstrains or args.mlsconstrain: print("MLS Constraints ({0} Added, {1} Removed)".format( len(diff.added_mlsconstrains), len(diff.removed_mlsconstrains))) if diff.added_mlsconstrains and not args.stats: print(" Added MLS Constraints: {0}".format( len(diff.added_mlsconstrains))) for r in sorted(diff.added_mlsconstrains): print(" + {0}".format(r)) if diff.removed_mlsconstrains and not args.stats: print(" Removed MLS Constraints: {0}".format( len(diff.removed_mlsconstrains))) for r in sorted(diff.removed_mlsconstrains): print(" - {0}".format(r)) print() del diff.added_mlsconstrains del diff.removed_mlsconstrains if all_differences or args.validatetrans: if diff.added_validatetrans or diff.removed_validatetrans or args.validatetrans: print("Validatetrans ({0} Added, {1} Removed)".format( len(diff.added_validatetrans), len(diff.removed_validatetrans))) if diff.added_validatetrans and not args.stats: print(" Added Validatetrans: {0}".format( len(diff.added_validatetrans))) for r in sorted(diff.added_validatetrans): print(" + {0}".format(r)) if diff.removed_validatetrans and not args.stats: print(" Removed Validatetrans: {0}".format( len(diff.removed_validatetrans))) for r in sorted(diff.removed_validatetrans): print(" - {0}".format(r)) print() del diff.added_validatetrans del diff.removed_validatetrans if all_differences or args.mlsvalidatetrans: if diff.added_mlsvalidatetrans or diff.removed_mlsvalidatetrans or args.mlsvalidatetrans: print("MLS Validatetrans ({0} Added, {1} Removed)".format( len(diff.added_mlsvalidatetrans), len(diff.removed_mlsvalidatetrans))) if diff.added_mlsvalidatetrans and not args.stats: print(" Added MLS Validatetrans: {0}".format( len(diff.added_mlsvalidatetrans))) for r in sorted(diff.added_mlsvalidatetrans): print(" + {0}".format(r)) if diff.removed_mlsvalidatetrans and not args.stats: print(" Removed MLS Validatetrans: {0}".format( len(diff.removed_mlsvalidatetrans))) for r in sorted(diff.removed_mlsvalidatetrans): print(" - {0}".format(r)) print() del diff.added_mlsvalidatetrans del diff.removed_mlsvalidatetrans if all_differences or args.initialsid: if diff.added_initialsids or diff.removed_initialsids or diff.modified_initialsids \ or args.initialsid: print("Initial SIDs ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_initialsids), len(diff.removed_initialsids), len(diff.modified_initialsids))) if diff.added_initialsids and not args.stats: print(" Added Initial SIDs: {0}".format(len(diff.added_initialsids))) for s in sorted(diff.added_initialsids): print(" + {0}".format(s.statement())) if diff.removed_initialsids and not args.stats: print(" Removed Initial SIDs: {0}".format(len(diff.removed_initialsids))) for s in sorted(diff.removed_initialsids): print(" - {0}".format(s.statement())) if diff.modified_initialsids and not args.stats: print(" Modified Initial SIDs: {0}".format(len(diff.modified_initialsids))) for name, mod in sorted(diff.modified_initialsids.items()): print(" * {0} +[{1.added_context}] -[{1.removed_context}];".format( name, mod)) print() del diff.added_initialsids del diff.removed_initialsids del diff.modified_initialsids if all_differences or args.fs_use: if diff.added_fs_uses or diff.removed_fs_uses or diff.modified_fs_uses \ or args.fs_use: print("Fs_use ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_fs_uses), len(diff.removed_fs_uses), len(diff.modified_fs_uses))) if diff.added_fs_uses and not args.stats: print(" Added Fs_use: {0}".format(len(diff.added_fs_uses))) for s in sorted(diff.added_fs_uses): print(" + {0}".format(s)) if diff.removed_fs_uses and not args.stats: print(" Removed Fs_use: {0}".format(len(diff.removed_fs_uses))) for s in sorted(diff.removed_fs_uses): print(" - {0}".format(s)) if diff.modified_fs_uses and not args.stats: print(" Modified Fs_use: {0}".format(len(diff.modified_fs_uses))) for entry in sorted(diff.modified_fs_uses, key=lambda x: x.rule): print(" * {0.ruletype} {0.fs} +[{1}] -[{2}];".format( entry.rule, entry.added_context, entry.removed_context)) print() del diff.added_fs_uses del diff.removed_fs_uses del diff.modified_fs_uses if all_differences or args.genfscon: if diff.added_genfscons or diff.removed_genfscons or diff.modified_genfscons \ or args.genfscon: print("Genfscons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_genfscons), len(diff.removed_genfscons), len(diff.modified_genfscons))) if diff.added_genfscons and not args.stats: print(" Added Genfscons: {0}".format(len(diff.added_genfscons))) for s in sorted(diff.added_genfscons): print(" + {0}".format(s)) if diff.removed_genfscons and not args.stats: print(" Removed Genfscons: {0}".format(len(diff.removed_genfscons))) for s in sorted(diff.removed_genfscons): print(" - {0}".format(s)) if diff.modified_genfscons and not args.stats: print(" Modified Genfscons: {0}".format(len(diff.modified_genfscons))) for entry in sorted(diff.modified_genfscons, key=lambda x: x.rule): print(" * genfscon {0.fs} {0.path} {0.filetype} +[{1}] -[{2}];".format( entry.rule, entry.added_context, entry.removed_context)) print() del diff.added_genfscons del diff.removed_genfscons del diff.modified_genfscons if all_differences or args.netifcon: if diff.added_netifcons or diff.removed_netifcons or \ diff.modified_netifcons or args.netifcon: print("Netifcons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_netifcons), len(diff.removed_netifcons), len(diff.modified_netifcons))) if diff.added_netifcons and not args.stats: print(" Added Netifcons: {0}".format(len(diff.added_netifcons))) for n in sorted(diff.added_netifcons): print(" + {0}".format(n)) if diff.removed_netifcons and not args.stats: print(" Removed Netifcons: {0}".format(len(diff.removed_netifcons))) for n in sorted(diff.removed_netifcons): print(" - {0}".format(n)) if diff.modified_netifcons and not args.stats: print(" Modified Netifcons: {0}".format(len(diff.modified_netifcons))) for entry in sorted(diff.modified_netifcons, key=lambda x: x.rule): # This output is different than other statements because # it becomes difficult to read if this was condensed # into a single line, especially if both contexts # are modified. change = [] if entry.removed_context: change.append("Modified Context") if entry.removed_packet: change.append("Modified Packet Context") print(" * {0.netif} ({1})".format(entry.rule, ", ".join(change))) if entry.removed_context: print(" Context:") print(" + {0}".format(entry.added_context)) print(" - {0}".format(entry.removed_context)) if entry.removed_packet: print(" Packet Context:") print(" + {0}".format(entry.added_packet)) print(" - {0}".format(entry.removed_packet)) print() del diff.added_netifcons del diff.removed_netifcons del diff.modified_netifcons if all_differences or args.nodecon: if diff.added_nodecons or diff.removed_nodecons or diff.modified_nodecons \ or args.nodecon: print("Nodecons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_nodecons), len(diff.removed_nodecons), len(diff.modified_nodecons))) if diff.added_nodecons and not args.stats: print(" Added Nodecons: {0}".format(len(diff.added_nodecons))) for n in sorted(diff.added_nodecons): print(" + {0}".format(n)) if diff.removed_nodecons and not args.stats: print(" Removed Nodecons: {0}".format(len(diff.removed_nodecons))) for n in sorted(diff.removed_nodecons): print(" - {0}".format(n)) if diff.modified_nodecons and not args.stats: print(" Modified Nodecons: {0}".format(len(diff.modified_nodecons))) for con, added_context, removed_context in sorted(diff.modified_nodecons, key=lambda x: x.rule): print(" * nodecon {0.address} {0.netmask} +[{1}] -[{2}];".format( con, added_context, removed_context)) print() del diff.added_nodecons del diff.removed_nodecons del diff.modified_nodecons if all_differences or args.portcon: if diff.added_portcons or diff.removed_portcons or diff.modified_portcons \ or args.portcon: print("Portcons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_portcons), len(diff.removed_portcons), len(diff.modified_portcons))) if diff.added_portcons and not args.stats: print(" Added Portcons: {0}".format(len(diff.added_portcons))) for n in sorted(diff.added_portcons): print(" + {0}".format(n)) if diff.removed_portcons and not args.stats: print(" Removed Portcons: {0}".format(len(diff.removed_portcons))) for n in sorted(diff.removed_portcons): print(" - {0}".format(n)) if diff.modified_portcons and not args.stats: print(" Modified Portcons: {0}".format(len(diff.modified_portcons))) for con, added_context, removed_context in sorted(diff.modified_portcons, key=lambda x: x.rule): low, high = con.ports if low == high: print(" * portcon {0.protocol} {1} +[{2}] -[{3}];".format( con, low, added_context, removed_context)) else: print(" * portcon {0.protocol} {1}-{2} +[{3}] -[{4}];".format( con, low, high, added_context, removed_context)) print() del diff.added_portcons del diff.removed_portcons del diff.modified_portcons if all_differences or args.polcap: if diff.added_polcaps or diff.removed_polcaps or args.polcap: print("Policy Capabilities ({0} Added, {1} Removed)".format( len(diff.added_polcaps), len(diff.removed_polcaps))) if diff.added_polcaps and not args.stats: print(" Added Policy Capabilities: {0}".format(len(diff.added_polcaps))) for n in sorted(diff.added_polcaps): print(" + {0}".format(n)) if diff.removed_polcaps and not args.stats: print(" Removed Policy Capabilities: {0}".format(len(diff.removed_polcaps))) for n in sorted(diff.removed_polcaps): print(" - {0}".format(n)) print() del diff.added_polcaps del diff.removed_polcaps if all_differences or args.default: if diff.added_defaults or diff.removed_defaults or diff.modified_defaults or args.default: print("Defaults ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_defaults), len(diff.removed_defaults), len(diff.modified_defaults))) if diff.added_defaults and not args.stats: print(" Added Defaults: {0}".format(len(diff.added_defaults))) for d in sorted(diff.added_defaults): print(" + {0}".format(d)) if diff.removed_defaults and not args.stats: print(" Removed Defaults: {0}".format(len(diff.removed_defaults))) for d in sorted(diff.removed_defaults): print(" - {0}".format(d)) if diff.modified_defaults and not args.stats: print(" Modified Defaults: {0}".format(len(diff.modified_defaults))) for default, added_default, removed_default, added_range, removed_range in sorted( diff.modified_defaults, key=lambda x: x.rule): line = " * {0.ruletype} {0.tclass} ".format(default) if removed_default: line += "+{0} -{1}".format(added_default, removed_default) else: line += default.default.name if removed_range: line += " +{0} -{1};".format(added_range, removed_range) else: try: line += " {0};".format(default.default_range) except AttributeError: line += ";" print(line) print() del diff.added_defaults del diff.removed_defaults del diff.modified_defaults if all_differences or args.typebounds: if diff.added_typebounds or diff.removed_typebounds or args.typebounds: print("Typebounds ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_typebounds), len(diff.removed_typebounds), len(diff.modified_typebounds))) if diff.added_typebounds and not args.stats: print(" Added Typebounds: {0}".format(len(diff.added_typebounds))) for d in sorted(diff.added_typebounds): print(" + {0}".format(d)) if diff.removed_typebounds and not args.stats: print(" Removed Typebounds: {0}".format(len(diff.removed_typebounds))) for d in sorted(diff.removed_typebounds): print(" - {0}".format(d)) if diff.modified_typebounds and not args.stats: print(" Modified Typebounds: {0}".format(len(diff.modified_typebounds))) for bound, added_bound, removed_bound in sorted( diff.modified_typebounds, key=lambda x: x.rule): print(" * {0.ruletype} +{1} -{2} {0.child};".format( bound, added_bound, removed_bound)) print() del diff.added_typebounds del diff.removed_typebounds except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/sedta000077500000000000000000000130071314142262400142330ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import sys import argparse import logging import setools def print_transition(trans): if trans.transition: print("Domain transition rule(s):") for t in trans.transition: print(t) if trans.setexec: print("\nSet execution context rule(s):") for s in trans.setexec: print(s) for entrypoint in trans.entrypoints: print("\nEntrypoint {0}:".format(entrypoint.name)) print("\tDomain entrypoint rule(s):") for e in entrypoint.entrypoint: print("\t{0}".format(e)) print("\n\tFile execute rule(s):") for e in entrypoint.execute: print("\t{0}".format(e)) if entrypoint.type_transition: print("\n\tType transition rule(s):") for t in entrypoint.type_transition: print("\t{0}".format(t)) print() if trans.dyntransition: print("Dynamic transition rule(s):") for d in trans.dyntransition: print(d) print("\nSet current process context rule(s):") for s in trans.setcurrent: print(s) print() print() parser = argparse.ArgumentParser( description="SELinux policy domain transition analysis tool.", epilog="If no analysis is selected, all forward transitions out of the source will be printed.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("-p", "--policy", help="Path to SELinux policy to analyze.") parser.add_argument("-s", "--source", help="Source type of the analysis.", required=True) parser.add_argument("-t", "--target", help="Target type of the analysis.") parser.add_argument("--stats", action="store_true", help="Display statistics at the end of the analysis.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") alg = parser.add_argument_group("Analysis algorithm") alg.add_argument("-S", "--shortest_path", action="store_true", help="Calculate all shortest paths.") alg.add_argument("-A", "--all_paths", type=int, metavar="MAX_STEPS", help="Calculate all paths, with the specified maximum path length. (Expensive)") opts = parser.add_argument_group("Analysis options") opts.add_argument("-r", "--reverse", action="store_true", default=False, help="Perform a reverse DTA.") opts.add_argument("-l", "--limit_trans", default=0, type=int, help="Limit to the specified number of transitions. Default is unlimited.") opts.add_argument("exclude", help="List of excluded types in the analysis.", nargs="*") args = parser.parse_args() if not args.target and (args.shortest_path or args.all_paths): parser.error("The target type must be specified to determine a path.") if args.target and not (args.shortest_path or args.all_paths): parser.error("An algorithm must be specified to determine a path.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) g = setools.DomainTransitionAnalysis(p, reverse=args.reverse, exclude=args.exclude) if args.shortest_path or args.all_paths: if args.shortest_path: paths = g.all_shortest_paths(args.source, args.target) else: paths = g.all_paths(args.source, args.target, args.all_paths) i = 0 for i, path in enumerate(paths, start=1): print("Domain transition path {0}:".format(i)) for stepnum, step in enumerate(path, start=1): print("Step {0}: {1} -> {2}\n".format(stepnum, step.source, step.target)) print_transition(step) if args.limit_trans and i >= args.limit_trans: break print(i, "domain transition path(s) found.") else: # single transition transitions = g.transitions(args.source) i = 0 for i, step in enumerate(transitions, start=1): print("Transition {0}: {1} -> {2}\n".format(i, step.source, step.target)) print_transition(step) if args.limit_trans and i >= args.limit_trans: break print(i, "domain transition(s) found.") if args.stats: print("\nGraph statistics:") print(g.get_stats()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/seinfo000077500000000000000000000405671314142262400144310ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import setools import argparse import sys import logging def expand_attr(attr): """Render type and role attributes.""" items = "\n\t".join(sorted(str(i) for i in attr.expand())) contents = items if items else "" return "{0}\n\t{1}".format(attr.statement(), contents) parser = argparse.ArgumentParser( description="SELinux policy information tool.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", help="Path to the SELinux policy to query.", nargs="?") parser.add_argument("-x", "--expand", action="store_true", help="Print additional information about the specified components.") parser.add_argument("--flat", help="Print without item count nor indentation.", dest="flat", default=False, action="store_true") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") queries = parser.add_argument_group("Component Queries") queries.add_argument("-a", "--attribute", help="Print type attributes.", dest="typeattrquery", nargs='?', const=True, metavar="ATTR") queries.add_argument("-b", "--bool", help="Print Booleans.", dest="boolquery", nargs='?', const=True, metavar="BOOL") queries.add_argument("-c", "--class", help="Print object classes.", dest="classquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("-r", "--role", help="Print roles.", dest="rolequery", nargs='?', const=True, metavar="ROLE") queries.add_argument("-t", "--type", help="Print types.", dest="typequery", nargs='?', const=True, metavar="TYPE") queries.add_argument("-u", "--user", help="Print users.", dest="userquery", nargs='?', const=True, metavar="USER") queries.add_argument("--category", help="Print MLS categories.", dest="mlscatsquery", nargs='?', const=True, metavar="CAT") queries.add_argument("--common", help="Print common permission set.", dest="commonquery", nargs='?', const=True, metavar="COMMON") queries.add_argument("--constrain", help="Print constraints.", dest="constraintquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--default", help="Print default_* rules.", dest="defaultquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--fs_use", help="Print fs_use statements.", dest="fsusequery", nargs='?', const=True, metavar="FS_TYPE") queries.add_argument("--genfscon", help="Print genfscon statements.", dest="genfsconquery", nargs='?', const=True, metavar="FS_TYPE") queries.add_argument("--initialsid", help="Print initial SIDs (contexts).", dest="initialsidquery", nargs='?', const=True, metavar="NAME") queries.add_argument("--netifcon", help="Print netifcon statements.", dest="netifconquery", nargs='?', const=True, metavar="DEVICE") queries.add_argument("--nodecon", help="Print nodecon statements.", dest="nodeconquery", nargs='?', const=True, metavar="ADDR") queries.add_argument("--permissive", help="Print permissive types.", dest="permissivequery", nargs='?', const=True, metavar="TYPE") queries.add_argument("--polcap", help="Print policy capabilities.", dest="polcapquery", nargs='?', const=True, metavar="NAME") queries.add_argument("--portcon", help="Print portcon statements.", dest="portconquery", nargs='?', const=True, metavar="PORTNUM[-PORTNUM]") queries.add_argument("--sensitivity", help="Print MLS sensitivities.", dest="mlssensquery", nargs='?', const=True, metavar="SENS") queries.add_argument("--typebounds", help="Print typebounds statements.", dest="typeboundsquery", nargs='?', const=True, metavar="BOUND_TYPE") queries.add_argument("--validatetrans", help="Print validatetrans.", dest="validatetransquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--all", help="Print all of the above. On a Xen policy, the Xen components " "will also be printed", dest="all", default=False, action="store_true") xen = parser.add_argument_group("Xen Component Queries") xen.add_argument("--ioportcon", help="Print all ioportcon statements.", dest="ioportconquery", default=False, action="store_true") xen.add_argument("--iomemcon", help="Print all iomemcon statements.", dest="iomemconquery", default=False, action="store_true") xen.add_argument("--pcidevicecon", help="Print all pcidevicecon statements.", dest="pcideviceconquery", default=False, action="store_true") xen.add_argument("--pirqcon", help="Print all pirqcon statements.", dest="pirqconquery", default=False, action="store_true") xen.add_argument("--devicetreecon", help="Print all devicetreecon statements.", dest="devicetreeconquery", default=False, action="store_true") args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) components = [] if args.boolquery or args.all: q = setools.BoolQuery(p) if isinstance(args.boolquery, str): q.name = args.boolquery components.append(("Booleans", q, lambda x: x.statement())) if args.mlscatsquery or args.all: q = setools.CategoryQuery(p) if isinstance(args.mlscatsquery, str): q.name = args.mlscatsquery components.append(("Categories", q, lambda x: x.statement())) if args.classquery or args.all: q = setools.ObjClassQuery(p) if isinstance(args.classquery, str): q.name = args.classquery components.append(("Classes", q, lambda x: x.statement())) if args.commonquery or args.all: q = setools.CommonQuery(p) if isinstance(args.commonquery, str): q.name = args.commonquery components.append(("Commons", q, lambda x: x.statement())) if args.constraintquery or args.all: q = setools.ConstraintQuery(p, ruletype=[setools.ConstraintRuletype.constrain, setools.ConstraintRuletype.mlsconstrain]) if isinstance(args.constraintquery, str): q.tclass = [args.constraintquery] components.append(("Constraints", q, lambda x: x.statement())) if args.defaultquery or args.all: q = setools.DefaultQuery(p) if isinstance(args.defaultquery, str): q.tclass = [args.defaultquery] components.append(("Default rules", q, lambda x: x.statement())) if args.fsusequery or args.all: q = setools.FSUseQuery(p) if isinstance(args.fsusequery, str): q.fs = args.fsusequery components.append(("Fs_use", q, lambda x: x.statement())) if args.genfsconquery or args.all: q = setools.GenfsconQuery(p) if isinstance(args.genfsconquery, str): q.fs = args.genfsconquery components.append(("Genfscon", q, lambda x: x.statement())) if args.initialsidquery or args.all: q = setools.InitialSIDQuery(p) if isinstance(args.initialsidquery, str): q.name = args.initialsidquery components.append(("Initial SIDs", q, lambda x: x.statement())) if args.netifconquery or args.all: q = setools.NetifconQuery(p) if isinstance(args.netifconquery, str): q.name = args.netifconquery components.append(("Netifcon", q, lambda x: x.statement())) if args.nodeconquery or args.all: q = setools.NodeconQuery(p) if isinstance(args.nodeconquery, str): q.network = args.nodeconquery components.append(("Nodecon", q, lambda x: x.statement())) if args.permissivequery or args.all: q = setools.TypeQuery(p, permissive=True, match_permissive=True) if isinstance(args.permissivequery, str): q.name = args.permissivequery components.append(("Permissive Types", q, lambda x: x.statement())) if args.polcapquery or args.all: q = setools.PolCapQuery(p) if isinstance(args.polcapquery, str): q.name = args.polcapquery components.append(("Polcap", q, lambda x: x.statement())) if args.portconquery or args.all: q = setools.PortconQuery(p) if isinstance(args.portconquery, str): try: ports = [int(i) for i in args.portconquery.split("-")] except ValueError: parser.error("Enter a port number or range, e.g. 22 or 6000-6020") if len(ports) == 2: q.ports = ports elif len(ports) == 1: q.ports = (ports[0], ports[0]) else: parser.error("Enter a port number or range, e.g. 22 or 6000-6020") components.append(("Portcon", q, lambda x: x.statement())) if args.rolequery or args.all: q = setools.RoleQuery(p) if isinstance(args.rolequery, str): q.name = args.rolequery components.append(("Roles", q, lambda x: x.statement())) if args.mlssensquery or args.all: q = setools.SensitivityQuery(p) if isinstance(args.mlssensquery, str): q.name = args.mlssensquery components.append(("Sensitivities", q, lambda x: x.statement())) if args.typeboundsquery or args.all: q = setools.BoundsQuery(p, ruletype=[setools.BoundsRuletype.typebounds]) if isinstance(args.typeboundsquery, str): q.child = args.typeboundsquery components.append(("Typebounds", q, lambda x: x.statement())) if args.typequery or args.all: q = setools.TypeQuery(p) if isinstance(args.typequery, str): q.name = args.typequery components.append(("Types", q, lambda x: x.statement())) if args.typeattrquery or args.all: q = setools.TypeAttributeQuery(p) if isinstance(args.typeattrquery, str): q.name = args.typeattrquery components.append(("Type Attributes", q, expand_attr)) if args.userquery or args.all: q = setools.UserQuery(p) if isinstance(args.userquery, str): q.name = args.userquery components.append(("Users", q, lambda x: x.statement())) if args.validatetransquery or args.all: q = setools.ConstraintQuery(p, ruletype=[setools.ConstraintRuletype.validatetrans, setools.ConstraintRuletype.mlsvalidatetrans]) if isinstance(args.validatetransquery, str): q.tclass = [args.validatetransquery] components.append(("Validatetrans", q, lambda x: x.statement())) if p.target_platform == "xen": if args.ioportconquery or args.all: q = setools.IoportconQuery(p) components.append(("Ioportcon", q, lambda x: x.statement())) if args.iomemconquery or args.all: q = setools.IomemconQuery(p) components.append(("Iomemcon", q, lambda x: x.statement())) if args.pcideviceconquery or args.all: q = setools.PcideviceconQuery(p) components.append(("Pcidevicecon", q, lambda x: x.statement())) if args.pirqconquery or args.all: q = setools.PirqconQuery(p) components.append(("Pirqcon", q, lambda x: x.statement())) if args.devicetreeconquery or args.all: q = setools.DevicetreeconQuery(p) components.append(("Devicetreecon", q, lambda x: x.statement())) if (not components or args.all) and not args.flat: mls = "enabled" if p.mls else "disabled" print("Statistics for policy file: {0}".format(p)) print("Policy Version: {0} (MLS {1})".format(p.version, mls)) print("Target Policy: {0}".format(p.target_platform)) print("Handle unknown classes: {0}".format(p.handle_unknown)) print(" Classes: {0:7} Permissions: {1:7}".format( p.class_count, p.permission_count)) print(" Sensitivities: {0:7} Categories: {1:7}".format( p.level_count, p.category_count)) print(" Types: {0:7} Attributes: {1:7}".format( p.type_count, p.type_attribute_count)) print(" Users: {0:7} Roles: {1:7}".format( p.user_count, p.role_count)) print(" Booleans: {0:7} Cond. Expr.: {1:7}".format( p.boolean_count, p.conditional_count)) print(" Allow: {0:7} Neverallow: {1:7}".format( p.allow_count, p.neverallow_count)) print(" Auditallow: {0:7} Dontaudit: {1:7}".format( p.auditallow_count, p.dontaudit_count)) print(" Type_trans: {0:7} Type_change: {1:7}".format( p.type_transition_count, p.type_change_count)) print(" Type_member: {0:7} Range_trans: {1:7}".format( p.type_member_count, p.range_transition_count)) print(" Role allow: {0:7} Role_trans: {1:7}".format( p.role_allow_count, p.role_transition_count)) print(" Constraints: {0:7} Validatetrans: {1:7}".format( p.constraint_count, p.validatetrans_count)) print(" MLS Constrain: {0:7} MLS Val. Tran: {1:7}".format( p.mlsconstraint_count, p.mlsvalidatetrans_count)) print(" Permissives: {0:7} Polcap: {1:7}".format( p.permissives_count, p.polcap_count)) print(" Defaults: {0:7} Typebounds: {1:7}".format( p.default_count, p.typebounds_count)) if p.target_platform == "selinux": print(" Allowxperm: {0:7} Neverallowxperm: {1:7}".format( p.allowxperm_count, p.neverallowxperm_count)) print(" Auditallowxperm: {0:7} Dontauditxperm: {1:7}".format( p.auditallowxperm_count, p.dontauditxperm_count)) print(" Initial SIDs: {0:7} Fs_use: {1:7}".format( p.initialsids_count, p.fs_use_count)) print(" Genfscon: {0:7} Portcon: {1:7}".format( p.genfscon_count, p.portcon_count)) print(" Netifcon: {0:7} Nodecon: {1:7}".format( p.netifcon_count, p.nodecon_count)) elif p.target_platform == "xen": print(" Initial SIDs: {0:7} Devicetreecon {1:7}".format( p.initialsids_count, p.devicetreecon_count)) print(" Iomemcon: {0:7} Ioportcon: {1:7}".format( p.iomemcon_count, p.ioportcon_count)) print(" Pcidevicecon: {0:7} Pirqcon: {1:7}".format( p.pcidevicecon_count, p.pirqcon_count)) for desc, component, expander in components: results = sorted(component.results()) if not args.flat: print("\n{0}: {1}".format(desc, len(results))) for item in results: result = expander(item) if args.expand else item strfmt = " {0}" if not args.flat else "{0}" print(strfmt.format(result)) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/seinfoflow000077500000000000000000000115551314142262400153140ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import setools import argparse import sys import logging parser = argparse.ArgumentParser( description="SELinux policy information flow analysis tool.", epilog="If no analysis is selected, all information flow out of the source will be printed.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("--stats", action="store_true", help="Display statistics at the end of the analysis.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") settings = parser.add_argument_group("Analysis settings") settings.add_argument("-p", "--policy", help="Path to SELinux policy to analyze.") settings.add_argument("-m", "--map", required=True, help="Path to permission map file.") settings.add_argument("-s", "--source", required=True, help="Source type of the analysis.") settings.add_argument("-t", "--target", default="", help="Target type of the analysis.") alg = parser.add_argument_group("Analysis algorithm") alg.add_argument("-S", "--shortest_path", action="store_true", help="Calculate all shortest paths.") alg.add_argument("-A", "--all_paths", type=int, metavar="MAX_STEPS", help="Calculate all paths, with the specified maximum path length. (Expensive)") opts = parser.add_argument_group("Analysis options") opts.add_argument("-w", "--min_weight", default=3, type=int, help="Minimum permission weight. Default is 3.") opts.add_argument("-l", "--limit_flows", default=0, type=int, help="Limit to the specified number of flows. Default is unlimited.") opts.add_argument("exclude", nargs="*", help="List of excluded types in the analysis.") args = parser.parse_args() if not args.target and (args.shortest_path or args.all_paths): parser.error("The target type must be specified to determine a path.") if args.target and not (args.shortest_path or args.all_paths): parser.error("A target type is not used for flows in/out of a type.") if args.limit_flows < 0: parser.error("Limit on information flows cannot be negative.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) m = setools.PermissionMap(args.map) g = setools.InfoFlowAnalysis(p, m, min_weight=args.min_weight, exclude=args.exclude) if args.shortest_path or args.all_paths: if args.shortest_path: paths = g.all_shortest_paths(args.source, args.target) else: paths = g.all_paths(args.source, args.target, args.all_paths) flownum = 0 for flownum, path in enumerate(paths, start=1): print("Flow {0}:".format(flownum)) for stepnum, step in enumerate(path, start=1): print(" Step {0}: {1} -> {2}".format(stepnum, step.source, step.target)) for rule in sorted(step.rules): print(" ", rule) print() if args.limit_flows and flownum >= args.limit_flows: break print() else: # single direct info flow flownum = 0 for flownum, flow in enumerate(g.infoflows(args.source), start=1): print("Flow {0}: {1} -> {2}".format(flownum, flow.source, flow.target)) for rule in sorted(flow.rules): print(" ", rule) print() if args.limit_flows and flownum >= args.limit_flows: break print(flownum, "information flow(s) found.") if args.stats: print("\nGraph statistics:") print(g.get_stats()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/sesearch000077500000000000000000000271321314142262400147340ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import setools import argparse import sys import logging parser = argparse.ArgumentParser( description="SELinux policy rule search tool.", epilog="TE/MLS rule searches cannot be mixed with RBAC rule searches.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", help="Path to the SELinux policy to search.", nargs="?") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") rtypes = parser.add_argument_group("TE Rule Types") rtypes.add_argument("-A", action="store_true", help="Search allow and allowxperm rules.") rtypes.add_argument("--allow", action="append_const", const=setools.TERuletype.allow, dest="tertypes", help="Search allow rules.") rtypes.add_argument("--allowxperm", action="append_const", const=setools.TERuletype.allowxperm, dest="tertypes", help="Search allowxperm rules.") rtypes.add_argument("--auditallow", action="append_const", const=setools.TERuletype.auditallow, dest="tertypes", help="Search auditallow rules.") rtypes.add_argument("--auditallowxperm", action="append_const", const=setools.TERuletype.auditallowxperm, dest="tertypes", help="Search auditallowxperm rules.") rtypes.add_argument("--dontaudit", action="append_const", const=setools.TERuletype.dontaudit, dest="tertypes", help="Search dontaudit rules.") rtypes.add_argument("--dontauditxperm", action="append_const", const=setools.TERuletype.dontauditxperm, dest="tertypes", help="Search dontauditxperm rules.") rtypes.add_argument("--neverallow", action="append_const", const=setools.TERuletype.neverallow, dest="tertypes", help="Search neverallow rules.") rtypes.add_argument("--neverallowxperm", action="append_const", const=setools.TERuletype.neverallowxperm, dest="tertypes", help="Search neverallowxperm rules.") rtypes.add_argument("-T", "--type_trans", action="append_const", const=setools.TERuletype.type_transition, dest="tertypes", help="Search type_transition rules.") rtypes.add_argument("--type_change", action="append_const", const=setools.TERuletype.type_change, dest="tertypes", help="Search type_change rules.") rtypes.add_argument("--type_member", action="append_const", const=setools.TERuletype.type_member, dest="tertypes", help="Search type_member rules.") rbacrtypes = parser.add_argument_group("RBAC Rule Types") rbacrtypes.add_argument("--role_allow", action="append_const", const=setools.RBACRuletype.allow, dest="rbacrtypes", help="Search role allow rules.") rbacrtypes.add_argument("--role_trans", action="append_const", const=setools.RBACRuletype.role_transition, dest="rbacrtypes", help="Search role_transition rules.") mlsrtypes = parser.add_argument_group("MLS Rule Types") mlsrtypes.add_argument("--range_trans", action="append_const", const=setools.MLSRuletype.range_transition, dest="mlsrtypes", help="Search range_transition rules.") expr = parser.add_argument_group("Expressions") expr.add_argument("-s", "--source", help="Source type/role of the TE/RBAC rule.") expr.add_argument("-t", "--target", help="Target type/role of the TE/RBAC rule.") expr.add_argument("-c", "--class", dest="tclass", help="Comma separated list of object classes") expr.add_argument("-p", "--perms", metavar="PERMS", help="Comma separated list of permissions.") expr.add_argument("-x", "--xperms", metavar="XPERMS", help="Comma separated list of extended permissions.") expr.add_argument("-D", "--default", help="Default of the rule. (type/role/range transition rules)") expr.add_argument("-b", "--bool", dest="boolean", metavar="BOOL", help="Comma separated list of Booleans in the conditional expression.") opts = parser.add_argument_group("Search options") opts.add_argument("-eb", action="store_true", dest="boolean_equal", help="Match Boolean list exactly instead of matching any listed Boolean.") opts.add_argument("-ep", action="store_true", dest="perms_equal", help="Match permission set exactly instead of matching any listed permission.") opts.add_argument("-ex", action="store_true", dest="xperms_equal", help="Match extended permission set exactly instead of matching any listed " "permission.") opts.add_argument("-ds", action="store_false", dest="source_indirect", help="Match source attributes directly instead of matching member types/roles.") opts.add_argument("-dt", action="store_false", dest="target_indirect", help="Match target attributes directly instead of matching member types/roles.") opts.add_argument("-rs", action="store_true", dest="source_regex", help="Use regular expression matching for the source type/role.") opts.add_argument("-rt", action="store_true", dest="target_regex", help="Use regular expression matching for the target type/role.") opts.add_argument("-rc", action="store_true", dest="tclass_regex", help="Use regular expression matching for the object class.") opts.add_argument("-rd", action="store_true", dest="default_regex", help="Use regular expression matching for the default type/role.") opts.add_argument("-rb", action="store_true", dest="boolean_regex", help="Use regular expression matching for Booleans.") args = parser.parse_args() if args.A: try: args.tertypes.extend([setools.TERuletype.allow, setools.TERuletype.allowxperm]) except AttributeError: args.tertypes = [setools.TERuletype.allow, setools.TERuletype.allowxperm] if not args.tertypes and not args.mlsrtypes and not args.rbacrtypes: parser.error("At least one rule type must be specified.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) if args.tertypes: q = setools.TERuleQuery(p, ruletype=args.tertypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, tclass_regex=args.tclass_regex, perms_equal=args.perms_equal, xperms_equal=args.xperms_equal, default=args.default, default_regex=args.default_regex, boolean_regex=args.boolean_regex, boolean_equal=args.boolean_equal) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: q.tclass = args.tclass else: q.tclass = args.tclass.split(",") if args.perms: q.perms = args.perms.split(",") if args.xperms: xperms = [] for item in args.xperms.split(","): rng = item.split("-") if len(rng) == 2: xperms.append((int(rng[0], base=16), int(rng[1], base=16))) elif len(rng) == 1: xperms.append((int(rng[0], base=16), int(rng[0], base=16))) else: parser.error("Enter an extended permission or extended permission range, e.g. " "0x5411 or 0x8800-0x88ff.") q.xperms = xperms if args.boolean: if args.boolean_regex: q.boolean = args.boolean else: q.boolean = args.boolean.split(",") for r in sorted(q.results()): print(r) if args.rbacrtypes: q = setools.RBACRuleQuery(p, ruletype=args.rbacrtypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, default=args.default, default_regex=args.default_regex, tclass_regex=args.tclass_regex) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: q.tclass = args.tclass else: q.tclass = args.tclass.split(",") for r in sorted(q.results()): print(r) if args.mlsrtypes: q = setools.MLSRuleQuery(p, ruletype=args.mlsrtypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, tclass_regex=args.tclass_regex, default=args.default) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: q.tclass = args.tclass else: q.tclass = args.tclass.split(",") for r in sorted(q.results()): print(r) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.1.1/setools/000077500000000000000000000000001314142262400146745ustar00rootroot00000000000000setools-4.1.1/setools/__init__.py000066400000000000000000000055511314142262400170130ustar00rootroot00000000000000"""The SETools SELinux policy analysis library.""" # Copyright 2014-2015, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # try: import pkg_resources # pylint: disable=no-member __version__ = pkg_resources.get_distribution("setools").version except ImportError: # pragma: no cover __version__ = "unknown" import logging # Python classes for policy representation from . import policyrep from .policyrep import SELinuxPolicy, BoundsRuletype, ConstraintRuletype, DefaultRuletype, \ DefaultRangeValue, DefaultValue, FSUseRuletype, HandleUnknown, MLSRuletype, \ NodeconIPVersion, PolicyTarget, PortconProtocol, RBACRuletype, TERuletype # Exceptions from . import exception # Component Queries from .boolquery import BoolQuery from .categoryquery import CategoryQuery from .commonquery import CommonQuery from .objclassquery import ObjClassQuery from .polcapquery import PolCapQuery from .rolequery import RoleQuery from .sensitivityquery import SensitivityQuery from .typequery import TypeQuery from .typeattrquery import TypeAttributeQuery from .userquery import UserQuery # Rule Queries from .mlsrulequery import MLSRuleQuery from .rbacrulequery import RBACRuleQuery from .terulequery import TERuleQuery # Constraint queries from .constraintquery import ConstraintQuery # Other queries from .boundsquery import BoundsQuery from .defaultquery import DefaultQuery # In-policy Context Queries from .fsusequery import FSUseQuery from .genfsconquery import GenfsconQuery from .initsidquery import InitialSIDQuery from .netifconquery import NetifconQuery from .nodeconquery import NodeconQuery from .portconquery import PortconQuery from .ioportconquery import IoportconQuery from .iomemconquery import IomemconQuery from .pirqconquery import PirqconQuery from .pcideviceconquery import PcideviceconQuery from .devicetreeconquery import DevicetreeconQuery # Information Flow Analysis from .infoflow import InfoFlowAnalysis from .permmap import PermissionMap # Domain Transition Analysis from .dta import DomainTransitionAnalysis # Policy difference from .diff import PolicyDifference logging.getLogger(__name__).addHandler(logging.NullHandler()) setools-4.1.1/setools/boolquery.py000066400000000000000000000042771314142262400173010ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .descriptors import CriteriaDescriptor from .mixins import MatchName from .query import PolicyQuery class BoolQuery(MatchName, PolicyQuery): """Query SELinux policy Booleans. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The Boolean name to match. name_regex If true, regular expression matching will be used on the Boolean name. default The default state to match. If this is None, the default state not be matched. """ _default = None @property def default(self): return self._default @default.setter def default(self, value): if value is None: self._default = None else: self._default = bool(value) def __init__(self, policy, **kwargs): super(BoolQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all Booleans matching the criteria.""" self.log.info("Generating Boolean results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Default: {0.default}".format(self)) for boolean in self.policy.bools(): if not self._match_name(boolean): continue if self.default is not None and boolean.state != self.default: continue yield boolean setools-4.1.1/setools/boundsquery.py000066400000000000000000000045461314142262400176370ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .policyrep import BoundsRuletype from .query import PolicyQuery from .util import match_regex class BoundsQuery(PolicyQuery): """ Query *bounds statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. """ ruletype = CriteriaSetDescriptor(enum_class=BoundsRuletype) parent = CriteriaDescriptor("parent_regex") parent_regex = False child = CriteriaDescriptor("child_regex") child_regex = False def __init__(self, policy, **kwargs): super(BoundsQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching *bounds statements.""" self.log.info("Generating bounds results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Parent: {0.parent!r}, regex: {0.parent_regex}".format(self)) self.log.debug("Child: {0.child!r}, regex: {0.child_regex}".format(self)) for b in self.policy.bounds(): if self.ruletype and b.ruletype not in self.ruletype: continue if self.parent and not match_regex( b.parent, self.parent, self.parent_regex): continue if self.child and not match_regex( b.child, self.child, self.child_regex): continue yield b setools-4.1.1/setools/categoryquery.py000066400000000000000000000036021314142262400201520ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchAlias, MatchName from .query import PolicyQuery class CategoryQuery(MatchAlias, MatchName, PolicyQuery): """ Query MLS Categories Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the category to match. name_regex If true, regular expression matching will be used for matching the name. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. """ def __init__(self, policy, **kwargs): super(CategoryQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching categories.""" self.log.info("Generating category results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) for cat in self.policy.categories(): if not self._match_name(cat): continue if not self._match_alias(cat): continue yield cat setools-4.1.1/setools/commonquery.py000066400000000000000000000041641314142262400176310ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .mixins import MatchName, MatchPermission from .query import PolicyQuery class CommonQuery(MatchPermission, MatchName, PolicyQuery): """ Query common permission sets. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the common to match. name_regex If true, regular expression matching will be used for matching the name. perms The permissions to match. perms_equal If true, only commons with permission sets that are equal to the criteria will match. Otherwise, any intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. """ def __init__(self, policy, **kwargs): super(CommonQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching commons.""" self.log.info("Generating common results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_perms_debug(self.log) for com in self.policy.commons(): if not self._match_name(com): continue if not self._match_perms(com): continue yield com setools-4.1.1/setools/constraintquery.py000066400000000000000000000130531314142262400205220ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchObjClass, MatchPermission from .policyrep import ConstraintRuletype from .policyrep.exception import ConstraintUseError from .query import PolicyQuery from .util import match_in_set class ConstraintQuery(MatchObjClass, MatchPermission, PolicyQuery): """ Query constraint rules, (mls)constrain/(mls)validatetrans. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. perms The permission(s) to match. perms_equal If true, the permission set of the rule must exactly match the permissions criteria. If false, any set intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. role The name of the role to match in the constraint expression. role_indirect If true, members of an attribute will be matched rather than the attribute itself. role_regex If true, regular expression matching will be used on the role. type_ The name of the type/attribute to match in the constraint expression. type_indirect If true, members of an attribute will be matched rather than the attribute itself. type_regex If true, regular expression matching will be used on the type/attribute. user The name of the user to match in the constraint expression. user_regex If true, regular expression matching will be used on the user. """ ruletype = CriteriaSetDescriptor(enum_class=ConstraintRuletype) user = CriteriaDescriptor("user_regex", "lookup_user") user_regex = False role = CriteriaDescriptor("role_regex", "lookup_role") role_regex = False role_indirect = True type_ = CriteriaDescriptor("type_regex", "lookup_type_or_attr") type_regex = False type_indirect = True def __init__(self, policy, **kwargs): super(ConstraintQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def _match_expr(self, expr, criteria, indirect, regex): """ Match roles/types/users in a constraint expression, optionally by expanding the contents of attributes. Parameters: expr The expression to match. criteria The criteria to match. indirect If attributes in the expression should be expanded. regex If regular expression matching should be used. """ if indirect: obj = set() for item in expr: obj.update(item.expand()) else: obj = expr return match_in_set(obj, criteria, regex) def results(self): """Generator which yields all matching constraints rules.""" self.log.info("Generating constraint results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self._match_object_class_debug(self.log) self._match_perms_debug(self.log) self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) for c in self.policy.constraints(): if self.ruletype: if c.ruletype not in self.ruletype: continue if not self._match_object_class(c): continue try: if not self._match_perms(c): continue except ConstraintUseError: continue if self.role and not self._match_expr( c.roles, self.role, self.role_indirect, self.role_regex): continue if self.type_ and not self._match_expr( c.types, self.type_, self.type_indirect, self.type_regex): continue if self.user and not self._match_expr( c.users, self.user, False, self.user_regex): continue yield c setools-4.1.1/setools/defaultquery.py000066400000000000000000000054611314142262400177660ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .query import PolicyQuery from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchObjClass from .policyrep import DefaultRuletype, DefaultValue, DefaultRangeValue class DefaultQuery(MatchObjClass, PolicyQuery): """ Query default_* statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. default The default to base new contexts (e.g. "source" or "target") default_range The range to use on new context, default_range only ("low", "high", "low_high") """ ruletype = CriteriaSetDescriptor(enum_class=DefaultRuletype) default = CriteriaDescriptor(enum_class=DefaultValue) default_range = CriteriaDescriptor(enum_class=DefaultRangeValue) def __init__(self, policy, **kwargs): super(DefaultQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching default_* statements.""" self.log.info("Generating default_* results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype!r}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}".format(self)) self.log.debug("Range: {0.default_range!r}".format(self)) for d in self.policy.defaults(): if self.ruletype and d.ruletype not in self.ruletype: continue if not self._match_object_class(d): continue if self.default and d.default != self.default: continue if self.default_range: try: if d.default_range != self.default_range: continue except AttributeError: continue yield d setools-4.1.1/setools/descriptors.py000066400000000000000000000165461314142262400176230ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # """ SETools descriptors. These classes override how a class's attributes are get/set/deleted. This is how the @property decorator works. See https://docs.python.org/3/howto/descriptor.html for more details. """ import re from collections import defaultdict from weakref import WeakKeyDictionary # # Query criteria descriptors # # Implementation note: if the name_regex attribute value # is changed the criteria must be reset. # class CriteriaDescriptor(object): """ Single item criteria descriptor. Keyword Parameters: name_regex The name of instance's regex setting attribute; used as name_regex below. If unset, regular expressions will never be used. lookup_function The name of the SELinuxPolicy lookup function, e.g. lookup_type or lookup_boolean. default_value The default value of the criteria. The default is None. enum_class The class of enumeration which supports a lookup class method. Read-only instance attribute use (obj parameter): policy The instance of SELinuxPolicy name_regex This attribute is read to determine if the criteria should be looked up or compiled into a regex. If the attribute does not exist, False is assumed. """ def __init__(self, name_regex=None, lookup_function=None, default_value=None, enum_class=None): assert name_regex or lookup_function or enum_class, \ "A simple attribute should be used if there is no regex, lookup function, or enum." assert not (lookup_function and enum_class), \ "Lookup functions and enum classes are mutually exclusive." self.regex = name_regex self.default_value = default_value self.lookup_function = lookup_function self.enum_class = enum_class # use weak references so instances can be # garbage collected, rather than unnecessarily # kept around due to this descriptor. self.instances = WeakKeyDictionary() def __get__(self, obj, objtype=None): if obj is None: return self return self.instances.setdefault(obj, self.default_value) def __set__(self, obj, value): if not value: self.instances[obj] = None elif self.regex and getattr(obj, self.regex, False): self.instances[obj] = re.compile(value) elif self.lookup_function: lookup = getattr(obj.policy, self.lookup_function) self.instances[obj] = lookup(value) elif self.enum_class: self.instances[obj] = self.enum_class.lookup(value) else: self.instances[obj] = value class CriteriaSetDescriptor(CriteriaDescriptor): """Descriptor for a set of criteria.""" def __set__(self, obj, value): if not value: self.instances[obj] = None elif self.regex and getattr(obj, self.regex, False): self.instances[obj] = re.compile(value) elif self.lookup_function: lookup = getattr(obj.policy, self.lookup_function) self.instances[obj] = set(lookup(v) for v in value) elif self.enum_class: self.instances[obj] = set(self.enum_class.lookup(v) for v in value) else: self.instances[obj] = set(value) # # NetworkX Graph Descriptors # # These descriptors are used to simplify all # of the dictionary use in the NetworkX graph. # class NetworkXGraphEdgeDescriptor(object): """ Descriptor base class for NetworkX graph edge attributes. Parameter: name The edge property name Instance class attribute use (obj parameter): G The NetworkX graph source The edge's source node target The edge's target node """ def __init__(self, propname): self.name = propname def __get__(self, obj, objtype=None): if obj is None: return self return obj.G[obj.source][obj.target][self.name] def __set__(self, obj, value): raise NotImplementedError def __delete__(self, obj): raise NotImplementedError class EdgeAttrDict(NetworkXGraphEdgeDescriptor): """A descriptor for edge attributes that are dictionaries.""" def __set__(self, obj, value): # None is a special value to initialize the attribute if value is None: obj.G[obj.source][obj.target][self.name] = defaultdict(list) else: raise ValueError("{0} dictionaries should not be assigned directly".format(self.name)) def __delete__(self, obj): obj.G[obj.source][obj.target][self.name].clear() class EdgeAttrIntMax(NetworkXGraphEdgeDescriptor): """ A descriptor for edge attributes that are non-negative integers that always keep the max assigned value until re-initialized. """ def __set__(self, obj, value): # None is a special value to initialize if value is None: obj.G[obj.source][obj.target][self.name] = 0 else: current_value = obj.G[obj.source][obj.target][self.name] obj.G[obj.source][obj.target][self.name] = max(current_value, value) class EdgeAttrList(NetworkXGraphEdgeDescriptor): """A descriptor for edge attributes that are lists.""" def __set__(self, obj, value): # None is a special value to initialize if value is None: obj.G[obj.source][obj.target][self.name] = [] else: raise ValueError("{0} lists should not be assigned directly".format(self.name)) def __delete__(self, obj): # in Python3 a .clear() function was added for lists # keep this implementation for Python 2 compat del obj.G[obj.source][obj.target][self.name][:] # # Permission map descriptors # class PermissionMapDescriptor(object): """ Descriptor for Permission Map mappings. Parameter: name The map setting name. validator A callable for validating the setting. Instance class attribute use (obj parameter): perm_map The full permission map. class_ The mapping's object class perm The mapping's permission """ def __init__(self, propname, validator): self.name = propname self.validator = validator def __get__(self, obj, objtype=None): if obj is None: return self return obj.perm_map[obj.class_][obj.perm][self.name] def __set__(self, obj, value): obj.perm_map[obj.class_][obj.perm][self.name] = self.validator(value) def __delete__(self, obj): raise AttributeError setools-4.1.1/setools/devicetreeconquery.py000066400000000000000000000053441314142262400211610ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext from .query import PolicyQuery class DevicetreeconQuery(MatchContext, PolicyQuery): """ Devicetreecon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: path A single devicetree path. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ path = None def __init__(self, policy, **kwargs): super(DevicetreeconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching devicetreecons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Path: {0.path!r}".format(self)) self._match_context_debug(self.log) for devicetreecon in self.policy.devicetreecons(): if self.path and self.path != devicetreecon.path: continue if not self._match_context(devicetreecon.context): continue yield devicetreecon setools-4.1.1/setools/diff/000077500000000000000000000000001314142262400156045ustar00rootroot00000000000000setools-4.1.1/setools/diff/__init__.py000066400000000000000000000057331314142262400177250ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .bool import BooleansDifference from .bounds import BoundsDifference from .commons import CommonDifference from .constraints import ConstraintsDifference from .default import DefaultsDifference from .fsuse import FSUsesDifference from .genfscon import GenfsconsDifference from .initsid import InitialSIDsDifference from .mls import CategoriesDifference, LevelDeclsDifference, SensitivitiesDifference from .mlsrules import MLSRulesDifference from .netifcon import NetifconsDifference from .nodecon import NodeconsDifference from .objclass import ObjClassDifference from .polcap import PolCapsDifference from .portcon import PortconsDifference from .properties import PropertiesDifference from .rbacrules import RBACRulesDifference from .roles import RolesDifference from .terules import TERulesDifference from .typeattr import TypeAttributesDifference from .types import TypesDifference from .users import UsersDifference __all__ = ['PolicyDifference'] class PolicyDifference(BooleansDifference, BoundsDifference, CategoriesDifference, CommonDifference, ConstraintsDifference, DefaultsDifference, FSUsesDifference, GenfsconsDifference, InitialSIDsDifference, LevelDeclsDifference, MLSRulesDifference, NetifconsDifference, NodeconsDifference, ObjClassDifference, PolCapsDifference, PortconsDifference, PropertiesDifference, RBACRulesDifference, RolesDifference, SensitivitiesDifference, TERulesDifference, TypeAttributesDifference, TypesDifference, UsersDifference): """ Determine the differences from the left policy to the right policy. Parameters: left A policy right A policy """ def _reset_diff(self): """Reset diff results on policy changes.""" for c in PolicyDifference.__bases__: c._reset_diff(self) setools-4.1.1/setools/diff/bool.py000066400000000000000000000046261314142262400171210ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_bool_record = namedtuple("modified_boolean", ["added_state", "removed_state"]) class BooleansDifference(Difference): """Determine the difference in type attributes between two policies.""" added_booleans = DiffResultDescriptor("diff_booleans") removed_booleans = DiffResultDescriptor("diff_booleans") modified_booleans = DiffResultDescriptor("diff_booleans") def diff_booleans(self): """Generate the difference in type attributes between the policies.""" self.log.info("Generating Boolean differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_booleans, self.removed_booleans, matched_booleans = \ self._set_diff( (SymbolWrapper(b) for b in self.left_policy.bools()), (SymbolWrapper(b) for b in self.right_policy.bools())) self.modified_booleans = dict() for left_boolean, right_boolean in matched_booleans: # Criteria for modified booleans # 1. change to default state if left_boolean.state != right_boolean.state: self.modified_booleans[left_boolean] = modified_bool_record(right_boolean.state, left_boolean.state) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting Boolean differences") self.added_booleans = None self.removed_booleans = None self.modified_booleans = None setools-4.1.1/setools/diff/bounds.py000066400000000000000000000100011314142262400174400ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from ..policyrep import BoundsRuletype from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper modified_bounds_record = namedtuple("modified_bound", ["rule", "added_bound", "removed_bound"]) class BoundsDifference(Difference): """Determine the difference in *bounds between two policies.""" added_typebounds = DiffResultDescriptor("diff_typebounds") removed_typebounds = DiffResultDescriptor("diff_typebounds") modified_typebounds = DiffResultDescriptor("diff_typebounds") # Lists of rules for each policy _left_typebounds = None _right_typebounds = None def diff_typebounds(self): """Generate the difference in typebound rules between the policies.""" self.log.info("Generating typebounds differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_typebounds is None or self._right_typebounds is None: self._create_typebound_lists() self.added_typebounds, self.removed_typebounds, matched_typebounds = self._set_diff( (BoundsWrapper(c) for c in self._left_typebounds), (BoundsWrapper(c) for c in self._right_typebounds), key=lambda b: str(b.child)) self.modified_typebounds = [] for left_bound, right_bound in matched_typebounds: if SymbolWrapper(left_bound.parent) != SymbolWrapper(right_bound.parent): self.modified_typebounds.append(modified_bounds_record( left_bound, right_bound.parent, left_bound.parent)) # # Internal functions # def _create_typebound_lists(self): """Create rule lists for both policies.""" self._left_typebounds = [] for rule in self.left_policy.bounds(): if rule.ruletype == BoundsRuletype.typebounds: self._left_typebounds.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) self._right_typebounds = [] for rule in self.right_policy.bounds(): if rule.ruletype == BoundsRuletype.typebounds: self._right_typebounds.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting all *bounds differences") self.added_typebounds = None self.removed_typebounds = None # Sets of rules for each policy self._left_typebounds = None self._right_typebounds = None class BoundsWrapper(Wrapper): """Wrap *bounds for diff purposes.""" __slots__ = ("ruletype", "parent", "child") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.parent = SymbolWrapper(rule.parent) self.child = SymbolWrapper(rule.child) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.child == other.child setools-4.1.1/setools/diff/commons.py000066400000000000000000000053561314142262400176420ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_commons_record = namedtuple("modified_common", ["added_perms", "removed_perms", "matched_perms"]) class CommonDifference(Difference): """ Determine the difference in common permission sets between two policies. """ added_commons = DiffResultDescriptor("diff_commons") removed_commons = DiffResultDescriptor("diff_commons") modified_commons = DiffResultDescriptor("diff_commons") def diff_commons(self): """Generate the difference in commons between the policies.""" self.log.info( "Generating common differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_commons, self.removed_commons, matched_commons = self._set_diff( (SymbolWrapper(c) for c in self.left_policy.commons()), (SymbolWrapper(c) for c in self.right_policy.commons())) self.modified_commons = dict() for left_common, right_common in matched_commons: # Criteria for modified commons # 1. change to permissions added_perms, removed_perms, matched_perms = self._set_diff(left_common.perms, right_common.perms) if added_perms or removed_perms: self.modified_commons[left_common] = modified_commons_record(added_perms, removed_perms, matched_perms) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting common differences") self.added_commons = None self.removed_commons = None self.modified_commons = None setools-4.1.1/setools/diff/conditional.py000066400000000000000000000021211314142262400204550ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .difference import Wrapper class ConditionalExprWrapper(Wrapper): """Wrap conditional policy expressions to allow comparisons by truth table.""" __slots__ = ("truth_table") def __init__(self, cond): self.origin = cond self.truth_table = cond.truth_table() def __eq__(self, other): return self.truth_table == other.truth_table setools-4.1.1/setools/diff/constraints.py000066400000000000000000000210151314142262400205240ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from ..policyrep import ConstraintRuletype from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper class ConstraintsDifference(Difference): """ Determine the difference in constraints between two policies. Since the compiler does not union constraints, there may be multiple constraints with the same ruletype, object class, and permission set, so constraints can only be added or removed, not modified. The constraint expressions are compared only on a basic level. Expressions that are logically equivalent but are structurally different, for example, by associativity, will be considered different. Type and role attributes are also not expanded, so if there are changes to attribute members, it will not be reflected as a difference. """ added_constrains = DiffResultDescriptor("diff_constrains") removed_constrains = DiffResultDescriptor("diff_constrains") added_mlsconstrains = DiffResultDescriptor("diff_mlsconstrains") removed_mlsconstrains = DiffResultDescriptor("diff_mlsconstrains") added_validatetrans = DiffResultDescriptor("diff_validatetrans") removed_validatetrans = DiffResultDescriptor("diff_validatetrans") added_mlsvalidatetrans = DiffResultDescriptor("diff_mlsvalidatetrans") removed_mlsvalidatetrans = DiffResultDescriptor("diff_mlsvalidatetrans") # Lists of rules for each policy _left_constrains = None _right_constrains = None _left_mlsconstrains = None _right_mlsconstrains = None _left_validatetrans = None _right_validatetrans = None _left_mlsvalidatetrans = None _right_mlsvalidatetrans = None def diff_constrains(self): """Generate the difference in constraint rules between the policies.""" self.log.info("Generating constraint differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_constrains is None or self._right_constrains is None: self._create_constrain_lists() self.added_constrains, self.removed_constrains, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_constrains), (ConstraintWrapper(c) for c in self._right_constrains)) def diff_mlsconstrains(self): """Generate the difference in MLS constraint rules between the policies.""" self.log.info( "Generating MLS constraint differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_mlsconstrains is None or self._right_mlsconstrains is None: self._create_constrain_lists() self.added_mlsconstrains, self.removed_mlsconstrains, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_mlsconstrains), (ConstraintWrapper(c) for c in self._right_mlsconstrains)) def diff_validatetrans(self): """Generate the difference in validatetrans rules between the policies.""" self.log.info( "Generating validatetrans differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_validatetrans is None or self._right_validatetrans is None: self._create_constrain_lists() self.added_validatetrans, self.removed_validatetrans, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_validatetrans), (ConstraintWrapper(c) for c in self._right_validatetrans)) def diff_mlsvalidatetrans(self): """Generate the difference in MLS validatetrans rules between the policies.""" self.log.info( "Generating mlsvalidatetrans differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_mlsvalidatetrans is None or self._right_mlsvalidatetrans is None: self._create_constrain_lists() self.added_mlsvalidatetrans, self.removed_mlsvalidatetrans, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_mlsvalidatetrans), (ConstraintWrapper(c) for c in self._right_mlsvalidatetrans)) # # Internal functions # def _create_constrain_lists(self): """Create rule lists for both policies.""" self._left_constrains = [] self._left_mlsconstrains = [] self._left_validatetrans = [] self._left_mlsvalidatetrans = [] for rule in self.left_policy.constraints(): if rule.ruletype == ConstraintRuletype.constrain: self._left_constrains.append(rule) elif rule.ruletype == ConstraintRuletype.mlsconstrain: self._left_mlsconstrains.append(rule) elif rule.ruletype == ConstraintRuletype.validatetrans: self._left_validatetrans.append(rule) elif rule.ruletype == ConstraintRuletype.mlsvalidatetrans: self._left_mlsvalidatetrans.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) self._right_constrains = [] self._right_mlsconstrains = [] self._right_validatetrans = [] self._right_mlsvalidatetrans = [] for rule in self.right_policy.constraints(): if rule.ruletype == ConstraintRuletype.constrain: self._right_constrains.append(rule) elif rule.ruletype == ConstraintRuletype.mlsconstrain: self._right_mlsconstrains.append(rule) elif rule.ruletype == ConstraintRuletype.validatetrans: self._right_validatetrans.append(rule) elif rule.ruletype == ConstraintRuletype.mlsvalidatetrans: self._right_mlsvalidatetrans.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting all constraints differences") self.added_constrains = None self.removed_constrains = None self.added_mlsconstrains = None self.removed_mlsconstrains = None self.added_validatetrans = None self.removed_validatetrans = None self.added_mlsvalidatetrans = None self.removed_mlsvalidatetrans = None # Sets of rules for each policy self._left_constrains = None self._left_mlsconstrains = None self._left_validatetrans = None self._left_mlsvalidatetrans = None self._right_constrains = None self._right_mlsconstrains = None self._right_validatetrans = None self._right_mlsvalidatetrans = None class ConstraintWrapper(Wrapper): """Wrap constraints for diff purposes.""" __slots__ = ("ruletype", "tclass", "perms", "expr") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.tclass = SymbolWrapper(rule.tclass) try: self.perms = rule.perms except AttributeError: # (mls)validatetrans self.perms = None self.key = hash(rule) self.expr = [] for op in rule.postfix_expression(): if isinstance(op, frozenset): # lists of types/users/roles self.expr.append(frozenset(SymbolWrapper(item) for item in op)) else: # strings in the expression such as u1/r1/t1 or "==" self.expr.append(op) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.tclass == other.tclass and \ self.perms == other.perms and \ self.expr == other.expr setools-4.1.1/setools/diff/context.py000066400000000000000000000027401314142262400176450ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from ..policyrep.exception import MLSDisabled from .difference import SymbolWrapper, Wrapper from .mls import RangeWrapper class ContextWrapper(Wrapper): """Wrap contexts to allow comparisons.""" __slots__ = ("user", "role", "type_", "range_") def __init__(self, ctx): self.origin = ctx self.user = SymbolWrapper(ctx.user) self.role = SymbolWrapper(ctx.role) self.type_ = SymbolWrapper(ctx.type_) try: self.range_ = RangeWrapper(ctx.range_) except MLSDisabled: self.range_ = None def __eq__(self, other): return self.user == other.user and \ self.role == other.role and \ self.type_ == other.type_ and \ self.range_ == other.range_ setools-4.1.1/setools/diff/default.py000066400000000000000000000102231314142262400176000ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper modified_default_record = namedtuple("modified_default", ["rule", "added_default", "removed_default", "added_default_range", "removed_default_range"]) class DefaultsDifference(Difference): """Determine the difference in default_* between two policies.""" added_defaults = DiffResultDescriptor("diff_defaults") removed_defaults = DiffResultDescriptor("diff_defaults") modified_defaults = DiffResultDescriptor("diff_defaults") def diff_defaults(self): """Generate the difference in type defaults between the policies.""" self.log.info( "Generating default_* differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_defaults, self.removed_defaults, matched_defaults = self._set_diff( (DefaultWrapper(d) for d in self.left_policy.defaults()), (DefaultWrapper(d) for d in self.right_policy.defaults())) self.modified_defaults = [] for left_default, right_default in matched_defaults: # Criteria for modified defaults # 1. change to default setting # 2. change to default range if left_default.default != right_default.default: removed_default = left_default.default added_default = right_default.default else: removed_default = None added_default = None try: if left_default.default_range != right_default.default_range: removed_default_range = left_default.default_range added_default_range = right_default.default_range else: removed_default_range = None added_default_range = None except AttributeError: removed_default_range = None added_default_range = None if removed_default or removed_default_range: self.modified_defaults.append( modified_default_record(left_default, added_default, removed_default, added_default_range, removed_default_range)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting default_* differences") self.added_defaults = None self.removed_defaults = None self.modified_defaults = None class DefaultWrapper(Wrapper): """Wrap default_* to allow comparisons.""" __slots__ = ("ruletype", "tclass") def __init__(self, default): self.origin = default self.ruletype = default.ruletype self.tclass = SymbolWrapper(default.tclass) self.key = hash(default) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.tclass == other.tclass setools-4.1.1/setools/diff/descriptors.py000066400000000000000000000031551314142262400205230ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from weakref import WeakKeyDictionary class DiffResultDescriptor(object): """Descriptor for managing diff results.""" # @properties could be used instead, but there are so # many result attributes, this will keep the code cleaner. def __init__(self, diff_function): self.diff_function = diff_function # use weak references so instances can be # garbage collected, rather than unnecessarily # kept around due to this descriptor. self.instances = WeakKeyDictionary() def __get__(self, obj, objtype=None): if obj is None: return self if self.instances.setdefault(obj, None) is None: diff = getattr(obj, self.diff_function) diff() return self.instances[obj] def __set__(self, obj, value): self.instances[obj] = value def __delete__(self, obj): self.instances[obj] = None setools-4.1.1/setools/diff/difference.py000066400000000000000000000130661314142262400202560ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from collections import namedtuple modified_item_record = namedtuple("modified_item", ["left", "right"]) class Difference(object): """Base class for all policy differences.""" def __init__(self, left_policy, right_policy): self.log = logging.getLogger(__name__) self.left_policy = left_policy self.right_policy = right_policy # # Policies to compare # @property def left_policy(self): return self._left_policy @left_policy.setter def left_policy(self, policy): self.log.info("Policy diff left policy set to {0}".format(policy)) self._left_policy = policy self._reset_diff() @property def right_policy(self): return self._right_policy @right_policy.setter def right_policy(self, policy): self.log.info("Policy diff right policy set to {0}".format(policy)) self._right_policy = policy self._reset_diff() # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" raise NotImplementedError @staticmethod def _expand_generator(rule_list, Wrapper): """Generator that yields a wrapped, expanded rule list.""" # this is to delay creating any containers # as long as possible, since rule lists # are typically massive. for unexpanded_rule in rule_list: for expanded_rule in unexpanded_rule.expand(): yield Wrapper(expanded_rule) @staticmethod def _set_diff(left, right, key=None): """ Standard diff of two sets. Parameters: left An iterable right An iterable Return: tuple (added, removed, matched) added Set of items in right but not left removed Set of items in left but not right matched Set of items in both left and right. This is in the form of tuples with the matching item from left and right """ left_items = set(left) right_items = set(right) added_items = right_items - left_items removed_items = left_items - right_items # The problem here is the symbol from both policies are # needed to build each tuple in the matched items set. # Using the standard Python set intersection code will only result # in one object. # # This tuple-generating code creates lists from the sets, to sort them. # This should result in all of the symbols lining up. If they don't, # this will break the caller. This should work since there is no remapping. # # This has extra checking to make sure this assertion holds, to fail # instead of giving wrong results. If there is a better way to, # ensure the items match up, please let me know how or submit a patch. matched_items = set() left_matched_items = sorted((left_items - removed_items), key=key) right_matched_items = sorted((right_items - added_items), key=key) assert len(left_matched_items) == len(right_matched_items), \ "Matched items assertion failure (this is an SETools bug), {0} != {1}". \ format(len(left_matched_items), len(right_matched_items)) for l, r in zip(left_matched_items, right_matched_items): assert l == r, \ "Matched items assertion failure (this is an SETools bug), {0} != {1}".format(l, r) matched_items.add((l, r)) try: # unwrap the objects return set(i.origin for i in added_items), \ set(i.origin for i in removed_items), \ set((l.origin, r.origin) for (l, r) in matched_items) except AttributeError: return added_items, removed_items, matched_items class Wrapper(object): """Base class for policy object wrappers.""" __slots__ = ("origin", "key") def __repr__(self): # pylint: disable=no-member return "<{0.__class__.__name__}(Wrapping {1})>".format(self, repr(self.origin)) def __hash__(self): raise NotImplementedError def __eq__(self, other): raise NotImplementedError def __lt__(self, other): raise NotImplementedError def __ne__(self, other): return not self == other class SymbolWrapper(Wrapper): """ General wrapper for policy symbols, e.g. types, roles to provide a diff-specific equality operation based on its name. """ __slots__ = ("name") def __init__(self, symbol): self.origin = symbol self.name = str(symbol) self.key = hash(self.name) def __hash__(self): return self.key def __lt__(self, other): return self.name < other.name def __eq__(self, other): return self.name == other.name setools-4.1.1/setools/diff/fsuse.py000066400000000000000000000061601314142262400173060ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper modified_fsuse_record = namedtuple("modified_fsuse", ["rule", "added_context", "removed_context"]) class FSUsesDifference(Difference): """Determine the difference in fs_use_* rules between two policies.""" added_fs_uses = DiffResultDescriptor("diff_fs_uses") removed_fs_uses = DiffResultDescriptor("diff_fs_uses") modified_fs_uses = DiffResultDescriptor("diff_fs_uses") def diff_fs_uses(self): """Generate the difference in fs_use rules between the policies.""" self.log.info( "Generating fs_use_* differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_fs_uses, self.removed_fs_uses, matched = self._set_diff( (FSUseWrapper(fs) for fs in self.left_policy.fs_uses()), (FSUseWrapper(fs) for fs in self.right_policy.fs_uses())) self.modified_fs_uses = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to context if ContextWrapper(left_rule.context) != ContextWrapper(right_rule.context): self.modified_fs_uses.append(modified_fsuse_record(left_rule, right_rule.context, left_rule.context)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting fs_use_* rule differences") self.added_fs_uses = None self.removed_fs_uses = None self.modified_fs_uses = None class FSUseWrapper(Wrapper): """Wrap fs_use_* rules to allow set operations.""" __slots__ = ("ruletype", "fs", "context") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.fs = rule.fs self.context = ContextWrapper(rule.context) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and self.fs == other.fs setools-4.1.1/setools/diff/genfscon.py000066400000000000000000000064061314142262400177660ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper modified_genfs_record = namedtuple("modified_genfs", ["rule", "added_context", "removed_context"]) class GenfsconsDifference(Difference): """Determine the difference in genfscon rules between two policies.""" added_genfscons = DiffResultDescriptor("diff_genfscons") removed_genfscons = DiffResultDescriptor("diff_genfscons") modified_genfscons = DiffResultDescriptor("diff_genfscons") def diff_genfscons(self): """Generate the difference in genfscon rules between the policies.""" self.log.info( "Generating genfscon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_genfscons, self.removed_genfscons, matched = self._set_diff( (GenfsconWrapper(fs) for fs in self.left_policy.genfscons()), (GenfsconWrapper(fs) for fs in self.right_policy.genfscons())) self.modified_genfscons = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to context if ContextWrapper(left_rule.context) != ContextWrapper(right_rule.context): self.modified_genfscons.append(modified_genfs_record(left_rule, right_rule.context, left_rule.context)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting genfscon rule differences") self.added_genfscons = None self.removed_genfscons = None self.modified_genfscons = None class GenfsconWrapper(Wrapper): """Wrap genfscon rules to allow set operations.""" __slots__ = ("fs", "path", "filetype", "context") def __init__(self, rule): self.origin = rule self.fs = rule.fs self.path = rule.path self.filetype = rule.filetype self.context = ContextWrapper(rule.context) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.fs == other.fs and \ self.path == other.path and \ self.filetype == other.filetype setools-4.1.1/setools/diff/initsid.py000066400000000000000000000047571314142262400176360ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_initsids_record = namedtuple("modified_initsid", ["added_context", "removed_context"]) class InitialSIDsDifference(Difference): """Determine the difference in initsids between two policies.""" added_initialsids = DiffResultDescriptor("diff_initialsids") removed_initialsids = DiffResultDescriptor("diff_initialsids") modified_initialsids = DiffResultDescriptor("diff_initialsids") def diff_initialsids(self): """Generate the difference in initial SIDs between the policies.""" self.log.info("Generating initial SID differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_initialsids, self.removed_initialsids, matched_initialsids = self._set_diff( (SymbolWrapper(i) for i in self.left_policy.initialsids()), (SymbolWrapper(i) for i in self.right_policy.initialsids())) self.modified_initialsids = dict() for left_initialsid, right_initialsid in matched_initialsids: # Criteria for modified initialsids # 1. change to context if ContextWrapper(left_initialsid.context) != ContextWrapper(right_initialsid.context): self.modified_initialsids[left_initialsid] = modified_initsids_record( right_initialsid.context, left_initialsid.context) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting initialsid differences") self.added_initialsids = None self.removed_initialsids = None self.modified_initialsids = None setools-4.1.1/setools/diff/mls.py000066400000000000000000000211651314142262400167560ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper modified_cat_record = namedtuple("modified_category", ["added_aliases", "removed_aliases", "matched_aliases"]) modified_sens_record = namedtuple("modified_sensitivity", ["added_aliases", "removed_aliases", "matched_aliases"]) modified_level_record = namedtuple("modified_level", ["level", "added_categories", "removed_categories", "matched_categories"]) class CategoriesDifference(Difference): """Determine the difference in categories between two policies.""" added_categories = DiffResultDescriptor("diff_categories") removed_categories = DiffResultDescriptor("diff_categories") modified_categories = DiffResultDescriptor("diff_categories") def diff_categories(self): """Generate the difference in categories between the policies.""" self.log.info( "Generating category differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_categories, self.removed_categories, matched_categories = self._set_diff( (SymbolWrapper(c) for c in self.left_policy.categories()), (SymbolWrapper(c) for c in self.right_policy.categories())) self.modified_categories = dict() for left_category, right_category in matched_categories: # Criteria for modified categories # 1. change to aliases added_aliases, removed_aliases, matched_aliases = self._set_diff( left_category.aliases(), right_category.aliases()) if added_aliases or removed_aliases: self.modified_categories[left_category] = modified_cat_record(added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting category differences") self.added_categories = None self.removed_categories = None self.modified_categories = None class SensitivitiesDifference(Difference): """Determine the difference in sensitivities between two policies.""" added_sensitivities = DiffResultDescriptor("diff_sensitivities") removed_sensitivities = DiffResultDescriptor("diff_sensitivities") modified_sensitivities = DiffResultDescriptor("diff_sensitivities") def diff_sensitivities(self): """Generate the difference in sensitivities between the policies.""" self.log.info( "Generating sensitivity differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_sensitivities, self.removed_sensitivities, matched_sensitivities = \ self._set_diff( (SymbolWrapper(s) for s in self.left_policy.sensitivities()), (SymbolWrapper(s) for s in self.right_policy.sensitivities())) self.modified_sensitivities = dict() for left_sens, right_sens in matched_sensitivities: # Criteria for modified sensitivities # 1. change to aliases added_aliases, removed_aliases, matched_aliases = self._set_diff( left_sens.aliases(), right_sens.aliases()) if added_aliases or removed_aliases: self.modified_sensitivities[left_sens] = modified_sens_record(added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting sensitivity differences") self.added_sensitivities = None self.removed_sensitivities = None self.modified_sensitivities = None class LevelDeclsDifference(Difference): """Determine the difference in levels between two policies.""" added_levels = DiffResultDescriptor("diff_levels") removed_levels = DiffResultDescriptor("diff_levels") modified_levels = DiffResultDescriptor("diff_levels") def diff_levels(self): """Generate the difference in levels between the policies.""" self.log.info( "Generating level decl differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_levels, self.removed_levels, matched_levels = \ self._set_diff( (LevelDeclWrapper(s) for s in self.left_policy.levels()), (LevelDeclWrapper(s) for s in self.right_policy.levels())) self.modified_levels = [] for left_level, right_level in matched_levels: # Criteria for modified levels # 1. change to allowed categories added_categories, removed_categories, matched_categories = self._set_diff( (SymbolWrapper(c) for c in left_level.categories()), (SymbolWrapper(c) for c in right_level.categories())) if added_categories or removed_categories: self.modified_levels.append(modified_level_record( left_level, added_categories, removed_categories, matched_categories)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting sensitivity differences") self.added_levels = None self.removed_levels = None self.modified_levels = None class LevelDeclWrapper(Wrapper): """Wrap level declarations to allow comparisons.""" __slots__ = ("sensitivity") def __init__(self, level): self.origin = level self.sensitivity = SymbolWrapper(level.sensitivity) self.key = hash(level) def __hash__(self): return self.key def __eq__(self, other): # non-MLS policies have no level declarations so there # should be no AttributeError possiblity here return self.sensitivity == other.sensitivity def __lt__(self, other): return self.sensitivity < other.sensitivity class LevelWrapper(Wrapper): """Wrap levels to allow comparisons.""" __slots__ = ("sensitivity", "categories") def __init__(self, level): self.origin = level self.sensitivity = SymbolWrapper(level.sensitivity) self.categories = set(SymbolWrapper(c) for c in level.categories()) def __eq__(self, other): try: return self.sensitivity == other.sensitivity and \ self.categories == other.categories except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False class RangeWrapper(Wrapper): """ Wrap ranges to allow comparisons. This only compares the low and high levels of the range. It does not detect additions/removals/modifications to levels between the low and high levels of the range. """ __slots__ = ("low", "high") def __init__(self, range_): self.origin = range_ self.low = LevelWrapper(range_.low) self.high = LevelWrapper(range_.high) def __eq__(self, other): try: return self.low == other.low and \ self.high == other.high except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False setools-4.1.1/setools/diff/mlsrules.py000066400000000000000000000113211314142262400200220ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict, namedtuple from ..policyrep import MLSRuletype from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper from .mls import RangeWrapper modified_mlsrule_record = namedtuple("modified_mlsrule", ["rule", "added_default", "removed_default"]) class MLSRulesDifference(Difference): """Determine the difference in MLS rules between two policies.""" added_range_transitions = DiffResultDescriptor("diff_range_transitions") removed_range_transitions = DiffResultDescriptor("diff_range_transitions") modified_range_transitions = DiffResultDescriptor("diff_range_transitions") # Lists of rules for each policy _left_mls_rules = defaultdict(list) _right_mls_rules = defaultdict(list) def diff_range_transitions(self): """Generate the difference in range_transition rules between the policies.""" self.log.info( "Generating range_transition differences from {0.left_policy} to {0.right_policy}". format(self)) if not self._left_mls_rules or not self._right_mls_rules: self._create_mls_rule_lists() added, removed, matched = self._set_diff( self._expand_generator(self._left_mls_rules[MLSRuletype.range_transition], MLSRuleWrapper), self._expand_generator(self._right_mls_rules[MLSRuletype.range_transition], MLSRuleWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default range if RangeWrapper(left_rule.default) != RangeWrapper(right_rule.default): modified.append(modified_mlsrule_record(left_rule, right_rule.default, left_rule.default)) self.added_range_transitions = added self.removed_range_transitions = removed self.modified_range_transitions = modified # # Internal functions # def _create_mls_rule_lists(self): """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self.log.debug("Building MLS rule lists from {0.left_policy}".format(self)) for rule in self.left_policy.mlsrules(): self._left_mls_rules[rule.ruletype].append(rule) self.log.debug("Building MLS rule lists from {0.right_policy}".format(self)) for rule in self.right_policy.mlsrules(): self._right_mls_rules[rule.ruletype].append(rule) self.log.debug("Completed building MLS rule lists.") def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting MLS rule differences") self.added_range_transitions = None self.removed_range_transitions = None self.modified_range_transitions = None # Sets of rules for each policy self._left_mls_rules.clear() self._right_mls_rules.clear() class MLSRuleWrapper(Wrapper): """Wrap MLS rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.tclass = SymbolWrapper(rule.tclass) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because MLSRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass setools-4.1.1/setools/diff/netifcon.py000066400000000000000000000073261314142262400177730ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper modified_netifcon_record = namedtuple("modified_netifcon", ["rule", "added_context", "removed_context", "added_packet", "removed_packet"]) class NetifconsDifference(Difference): """Determine the difference in netifcons between two policies.""" added_netifcons = DiffResultDescriptor("diff_netifcons") removed_netifcons = DiffResultDescriptor("diff_netifcons") modified_netifcons = DiffResultDescriptor("diff_netifcons") def diff_netifcons(self): """Generate the difference in netifcons between the policies.""" self.log.info("Generating netifcon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_netifcons, self.removed_netifcons, matched_netifcons = self._set_diff( (NetifconWrapper(n) for n in self.left_policy.netifcons()), (NetifconWrapper(n) for n in self.right_policy.netifcons())) self.modified_netifcons = [] for left_netifcon, right_netifcon in matched_netifcons: # Criteria for modified netifcons # 1. change to context # 2. change to packet context if ContextWrapper(left_netifcon.context) != ContextWrapper(right_netifcon.context): removed_context = left_netifcon.context added_context = right_netifcon.context else: removed_context = None added_context = None if ContextWrapper(left_netifcon.packet) != ContextWrapper(right_netifcon.packet): removed_packet = left_netifcon.packet added_packet = right_netifcon.packet else: removed_packet = None added_packet = None if removed_context or removed_packet: self.modified_netifcons.append(modified_netifcon_record( left_netifcon, added_context, removed_context, added_packet, removed_packet)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting netifcon differences") self.added_netifcons = None self.removed_netifcons = None self.modified_netifcons = None class NetifconWrapper(Wrapper): """Wrap netifcon statements for diff purposes.""" __slots__ = ("netif") def __init__(self, ocon): self.origin = ocon self.netif = ocon.netif self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.netif < other.netif def __eq__(self, other): return self.netif == other.netif setools-4.1.1/setools/diff/nodecon.py000066400000000000000000000064111314142262400176050ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper modified_nodecon_record = namedtuple("modified_nodecon", ["rule", "added_context", "removed_context"]) class NodeconsDifference(Difference): """Determine the difference in nodecons between two policies.""" added_nodecons = DiffResultDescriptor("diff_nodecons") removed_nodecons = DiffResultDescriptor("diff_nodecons") modified_nodecons = DiffResultDescriptor("diff_nodecons") def diff_nodecons(self): """Generate the difference in nodecons between the policies.""" self.log.info("Generating nodecon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_nodecons, self.removed_nodecons, matched_nodecons = self._set_diff( (NodeconWrapper(n) for n in self.left_policy.nodecons()), (NodeconWrapper(n) for n in self.right_policy.nodecons())) self.modified_nodecons = [] for left_nodecon, right_nodecon in matched_nodecons: # Criteria for modified nodecons # 1. change to context if ContextWrapper(left_nodecon.context) != ContextWrapper(right_nodecon.context): self.modified_nodecons.append(modified_nodecon_record(left_nodecon, right_nodecon.context, left_nodecon.context)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting nodecon differences") self.added_nodecons = None self.removed_nodecons = None self.modified_nodecons = None class NodeconWrapper(Wrapper): """Wrap nodecon statements for diff purposes.""" __slots__ = ("ip_version", "address", "netmask") def __init__(self, ocon): self.origin = ocon self.ip_version = ocon.ip_version self.address = ocon.address self.netmask = ocon.netmask self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.ip_version == other.ip_version and \ self.address == other.address and \ self.netmask == other.netmask setools-4.1.1/setools/diff/objclass.py000066400000000000000000000060571314142262400177660ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from ..policyrep.exception import NoCommon from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_classes_record = namedtuple("modified_class", ["added_perms", "removed_perms", "matched_perms"]) class ObjClassDifference(Difference): """ Determine the difference in object classes between two policies. """ added_classes = DiffResultDescriptor("diff_classes") removed_classes = DiffResultDescriptor("diff_classes") modified_classes = DiffResultDescriptor("diff_classes") def diff_classes(self): """Generate the difference in object classes between the policies.""" self.log.info( "Generating class differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_classes, self.removed_classes, matched_classes = self._set_diff( (SymbolWrapper(c) for c in self.left_policy.classes()), (SymbolWrapper(c) for c in self.right_policy.classes())) self.modified_classes = dict() for left_class, right_class in matched_classes: # Criteria for modified classes # 1. change to permissions (inherited common is expanded) left_perms = left_class.perms try: left_perms |= left_class.common.perms except NoCommon: pass right_perms = right_class.perms try: right_perms |= right_class.common.perms except NoCommon: pass added_perms, removed_perms, matched_perms = self._set_diff(left_perms, right_perms) if added_perms or removed_perms: self.modified_classes[left_class] = modified_classes_record(added_perms, removed_perms, matched_perms) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting object class differences") self.added_classes = None self.removed_classes = None self.modified_classes = None setools-4.1.1/setools/diff/polcap.py000066400000000000000000000033161314142262400174370ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper class PolCapsDifference(Difference): """Determine the difference in polcaps between two policies.""" added_polcaps = DiffResultDescriptor("diff_polcaps") removed_polcaps = DiffResultDescriptor("diff_polcaps") def diff_polcaps(self): """Generate the difference in polcaps between the policies.""" self.log.info("Generating policy cap differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_polcaps, self.removed_polcaps, _ = self._set_diff( (SymbolWrapper(n) for n in self.left_policy.polcaps()), (SymbolWrapper(n) for n in self.right_policy.polcaps())) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting policy capability differences") self.added_polcaps = None self.removed_polcaps = None setools-4.1.1/setools/diff/portcon.py000066400000000000000000000063131314142262400176450ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper modified_portcon_record = namedtuple("modified_portcon", ["rule", "added_context", "removed_context"]) class PortconsDifference(Difference): """Determine the difference in portcons between two policies.""" added_portcons = DiffResultDescriptor("diff_portcons") removed_portcons = DiffResultDescriptor("diff_portcons") modified_portcons = DiffResultDescriptor("diff_portcons") def diff_portcons(self): """Generate the difference in portcons between the policies.""" self.log.info("Generating portcon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_portcons, self.removed_portcons, matched_portcons = self._set_diff( (PortconWrapper(n) for n in self.left_policy.portcons()), (PortconWrapper(n) for n in self.right_policy.portcons())) self.modified_portcons = [] for left_portcon, right_portcon in matched_portcons: # Criteria for modified portcons # 1. change to context if ContextWrapper(left_portcon.context) != ContextWrapper(right_portcon.context): self.modified_portcons.append(modified_portcon_record(left_portcon, right_portcon.context, left_portcon.context)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting portcon differences") self.added_portcons = None self.removed_portcons = None self.modified_portcons = None class PortconWrapper(Wrapper): """Wrap portcon statements for diff purposes.""" __slots__ = ("protocol", "low", "high") def __init__(self, ocon): self.origin = ocon self.protocol = ocon.protocol self.low, self.high = ocon.ports self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.protocol == other.protocol and \ self.low == other.low and \ self.high == other.high setools-4.1.1/setools/diff/properties.py000066400000000000000000000045251314142262400203600ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference modified_properties_record = namedtuple("modified_property", ["property", "added", "removed"]) class PropertiesDifference(Difference): """ Determine the difference in policy properties (unknown permissions, MLS, etc.) between two policies. """ modified_properties = DiffResultDescriptor("diff_properties") def diff_properties(self): self.modified_properties = [] if self.left_policy.handle_unknown != self.right_policy.handle_unknown: self.modified_properties.append( modified_properties_record("handle_unknown", self.right_policy.handle_unknown, self.left_policy.handle_unknown)) if self.left_policy.mls != self.right_policy.mls: self.modified_properties.append( modified_properties_record("MLS", self.right_policy.mls, self.left_policy.mls)) if self.left_policy.version != self.right_policy.version: self.modified_properties.append( modified_properties_record("version", self.right_policy.version, self.left_policy.version)) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting property differences") self.modified_properties = None setools-4.1.1/setools/diff/rbacrules.py000066400000000000000000000144711314142262400201470ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict, namedtuple from ..policyrep import RBACRuletype from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper modified_rbacrule_record = namedtuple("modified_rbacrule", ["rule", "added_default", "removed_default"]) class RBACRulesDifference(Difference): """Determine the difference in RBAC rules between two policies.""" added_role_allows = DiffResultDescriptor("diff_role_allows") removed_role_allows = DiffResultDescriptor("diff_role_allows") # role allows cannot be modified, only added/removed added_role_transitions = DiffResultDescriptor("diff_role_transitions") removed_role_transitions = DiffResultDescriptor("diff_role_transitions") modified_role_transitions = DiffResultDescriptor("diff_role_transitions") # Lists of rules for each policy _left_rbac_rules = defaultdict(list) _right_rbac_rules = defaultdict(list) def diff_role_allows(self): """Generate the difference in role allow rules between the policies.""" self.log.info( "Generating role allow differences from {0.left_policy} to {0.right_policy}". format(self)) if not self._left_rbac_rules or not self._right_rbac_rules: self._create_rbac_rule_lists() self.added_role_allows, self.removed_role_allows, _ = self._set_diff( self._expand_generator(self._left_rbac_rules[RBACRuletype.allow], RoleAllowWrapper), self._expand_generator(self._right_rbac_rules[RBACRuletype.allow], RoleAllowWrapper)) def diff_role_transitions(self): """Generate the difference in role_transition rules between the policies.""" self.log.info( "Generating role_transition differences from {0.left_policy} to {0.right_policy}". format(self)) if not self._left_rbac_rules or not self._right_rbac_rules: self._create_rbac_rule_lists() added, removed, matched = self._set_diff( self._expand_generator(self._left_rbac_rules[RBACRuletype.role_transition], RoleTransitionWrapper), self._expand_generator(self._right_rbac_rules[RBACRuletype.role_transition], RoleTransitionWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default role if SymbolWrapper(left_rule.default) != SymbolWrapper(right_rule.default): modified.append(modified_rbacrule_record(left_rule, right_rule.default, left_rule.default)) self.added_role_transitions = added self.removed_role_transitions = removed self.modified_role_transitions = modified # # Internal functions # def _create_rbac_rule_lists(self): """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self.log.debug("Building RBAC rule lists from {0.left_policy}".format(self)) for rule in self.left_policy.rbacrules(): self._left_rbac_rules[rule.ruletype].append(rule) self.log.debug("Building RBAC rule lists from {0.right_policy}".format(self)) for rule in self.right_policy.rbacrules(): self._right_rbac_rules[rule.ruletype].append(rule) self.log.debug("Completed building RBAC rule lists.") def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting RBAC rule differences") self.added_role_allows = None self.removed_role_allows = None self.modified_role_allows = None self.added_role_transitions = None self.removed_role_transitions = None self.modified_role_transitions = None # Sets of rules for each policy self._left_rbac_rules.clear() self._right_rbac_rules.clear() class RoleAllowWrapper(Wrapper): """Wrap role allow rules to allow set operations.""" __slots__ = ("ruletype", "source", "target") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because RBACRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and self.target == other.target class RoleTransitionWrapper(Wrapper): """Wrap role_transition rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.tclass = SymbolWrapper(rule.tclass) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because RBACRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass setools-4.1.1/setools/diff/roles.py000066400000000000000000000053201314142262400173020ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_roles_record = namedtuple("modified_role", ["added_types", "removed_types", "matched_types"]) class RolesDifference(Difference): """Determine the difference in roles between two policies.""" added_roles = DiffResultDescriptor("diff_roles") removed_roles = DiffResultDescriptor("diff_roles") modified_roles = DiffResultDescriptor("diff_roles") def diff_roles(self): """Generate the difference in roles between the policies.""" self.log.info( "Generating role differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_roles, self.removed_roles, matched_roles = self._set_diff( (SymbolWrapper(r) for r in self.left_policy.roles()), (SymbolWrapper(r) for r in self.right_policy.roles())) self.modified_roles = dict() for left_role, right_role in matched_roles: # Criteria for modified roles # 1. change to type set, or # 2. change to attribute set (not implemented) added_types, removed_types, matched_types = self._set_diff( (SymbolWrapper(t) for t in left_role.types()), (SymbolWrapper(t) for t in right_role.types())) if added_types or removed_types: self.modified_roles[left_role] = modified_roles_record(added_types, removed_types, matched_types) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting role differences") self.added_roles = None self.removed_roles = None self.modified_roles = None setools-4.1.1/setools/diff/terules.py000066400000000000000000000403601314142262400176440ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict, namedtuple from ..policyrep import IoctlSet, TERuletype from ..policyrep.exception import RuleNotConditional, RuleUseError, TERuleNoFilename from .conditional import ConditionalExprWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper modified_avrule_record = namedtuple("modified_avrule", ["rule", "added_perms", "removed_perms", "matched_perms"]) modified_terule_record = namedtuple("modified_terule", ["rule", "added_default", "removed_default"]) def _avrule_expand_generator(rule_list, Wrapper): """ Generator that yields wrapped, expanded, av(x) rules with unioned permission sets. """ items = dict() for unexpanded_rule in rule_list: for expanded_rule in unexpanded_rule.expand(): expanded_wrapped_rule = Wrapper(expanded_rule) # create a hash table (dict) with the first rule # as the key and value. Rules where permission sets should # be unioned together have the same hash, so this will union # the permissions together. try: items[expanded_wrapped_rule].origin.perms |= expanded_wrapped_rule.origin.perms except KeyError: items[expanded_wrapped_rule] = expanded_wrapped_rule return items.keys() def av_diff_template(ruletype): """ This is a template for the access vector diff functions. Parameters: ruletype The rule type, e.g. "allow". """ ruletype = TERuletype.lookup(ruletype) def diff(self): """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if not self._left_te_rules or not self._right_te_rules: self._create_te_rule_lists() added, removed, matched = self._set_diff( _avrule_expand_generator(self._left_te_rules[ruletype], AVRuleWrapper), _avrule_expand_generator(self._right_te_rules[ruletype], AVRuleWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to permissions added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, right_rule.perms) # the final set comprehension is to avoid having lists # like [("perm1", "perm1"), ("perm2", "perm2")], as the # matched_perms return from _set_diff is a set of tuples if added_perms or removed_perms: modified.append(modified_avrule_record(left_rule, added_perms, removed_perms, set(p[0] for p in matched_perms))) setattr(self, "added_{0}s".format(ruletype), added) setattr(self, "removed_{0}s".format(ruletype), removed) setattr(self, "modified_{0}s".format(ruletype), modified) return diff def avx_diff_template(ruletype): """ This is a template for the extended permission access vector diff functions. Parameters: ruletype The rule type, e.g. "allowxperm". """ ruletype = TERuletype.lookup(ruletype) def diff(self): """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if not self._left_te_rules or not self._right_te_rules: self._create_te_rule_lists() added, removed, matched = self._set_diff( _avrule_expand_generator(self._left_te_rules[ruletype], AVRuleXpermWrapper), _avrule_expand_generator(self._right_te_rules[ruletype], AVRuleXpermWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to permissions added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, right_rule.perms) # the final set comprehension is to avoid having lists # like [("perm1", "perm1"), ("perm2", "perm2")], as the # matched_perms return from _set_diff is a set of tuples if added_perms or removed_perms: modified.append(modified_avrule_record(left_rule, IoctlSet(added_perms), IoctlSet(removed_perms), IoctlSet(p[0] for p in matched_perms))) setattr(self, "added_{0}s".format(ruletype), added) setattr(self, "removed_{0}s".format(ruletype), removed) setattr(self, "modified_{0}s".format(ruletype), modified) return diff def te_diff_template(ruletype): """ This is a template for the type_* diff functions. Parameters: ruletype The rule type, e.g. "type_transition". """ ruletype = TERuletype.lookup(ruletype) def diff(self): """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if not self._left_te_rules or not self._right_te_rules: self._create_te_rule_lists() added, removed, matched = self._set_diff( self._expand_generator(self._left_te_rules[ruletype], TERuleWrapper), self._expand_generator(self._right_te_rules[ruletype], TERuleWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default type if SymbolWrapper(left_rule.default) != SymbolWrapper(right_rule.default): modified.append(modified_terule_record(left_rule, right_rule.default, left_rule.default)) setattr(self, "added_{0}s".format(ruletype), added) setattr(self, "removed_{0}s".format(ruletype), removed) setattr(self, "modified_{0}s".format(ruletype), modified) return diff class TERulesDifference(Difference): """ Determine the difference in type enforcement rules between two policies. """ diff_allows = av_diff_template("allow") added_allows = DiffResultDescriptor("diff_allows") removed_allows = DiffResultDescriptor("diff_allows") modified_allows = DiffResultDescriptor("diff_allows") diff_auditallows = av_diff_template("auditallow") added_auditallows = DiffResultDescriptor("diff_auditallows") removed_auditallows = DiffResultDescriptor("diff_auditallows") modified_auditallows = DiffResultDescriptor("diff_auditallows") diff_neverallows = av_diff_template("neverallow") added_neverallows = DiffResultDescriptor("diff_neverallows") removed_neverallows = DiffResultDescriptor("diff_neverallows") modified_neverallows = DiffResultDescriptor("diff_neverallows") diff_dontaudits = av_diff_template("dontaudit") added_dontaudits = DiffResultDescriptor("diff_dontaudits") removed_dontaudits = DiffResultDescriptor("diff_dontaudits") modified_dontaudits = DiffResultDescriptor("diff_dontaudits") diff_allowxperms = avx_diff_template("allowxperm") added_allowxperms = DiffResultDescriptor("diff_allowxperms") removed_allowxperms = DiffResultDescriptor("diff_allowxperms") modified_allowxperms = DiffResultDescriptor("diff_allowxperms") diff_auditallowxperms = avx_diff_template("auditallowxperm") added_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") removed_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") modified_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") diff_neverallowxperms = avx_diff_template("neverallowxperm") added_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") removed_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") modified_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") diff_dontauditxperms = avx_diff_template("dontauditxperm") added_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") removed_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") modified_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") diff_type_transitions = te_diff_template("type_transition") added_type_transitions = DiffResultDescriptor("diff_type_transitions") removed_type_transitions = DiffResultDescriptor("diff_type_transitions") modified_type_transitions = DiffResultDescriptor("diff_type_transitions") diff_type_changes = te_diff_template("type_change") added_type_changes = DiffResultDescriptor("diff_type_changes") removed_type_changes = DiffResultDescriptor("diff_type_changes") modified_type_changes = DiffResultDescriptor("diff_type_changes") diff_type_members = te_diff_template("type_member") added_type_members = DiffResultDescriptor("diff_type_members") removed_type_members = DiffResultDescriptor("diff_type_members") modified_type_members = DiffResultDescriptor("diff_type_members") # Lists of rules for each policy _left_te_rules = defaultdict(list) _right_te_rules = defaultdict(list) # # Internal functions # def _create_te_rule_lists(self): """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self.log.debug("Building TE rule lists from {0.left_policy}".format(self)) for rule in self.left_policy.terules(): self._left_te_rules[rule.ruletype].append(rule) self.log.debug("Building TE rule lists from {0.right_policy}".format(self)) for rule in self.right_policy.terules(): self._right_te_rules[rule.ruletype].append(rule) self.log.debug("Completed building TE rule lists.") def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting TE rule differences") self.added_allows = None self.removed_allows = None self.modified_allows = None self.added_auditallows = None self.removed_auditallows = None self.modified_auditallows = None self.added_neverallows = None self.removed_neverallows = None self.modified_neverallows = None self.added_dontaudits = None self.removed_dontaudits = None self.modified_dontaudits = None self.added_allowxperms = None self.removed_allowxperms = None self.modified_allowxperms = None self.added_auditallowxperms = None self.removed_auditallowxperms = None self.modified_auditallowxperms = None self.added_neverallowxperms = None self.removed_neverallowxperms = None self.modified_neverallowxperms = None self.added_dontauditxperms = None self.removed_dontauditxperms = None self.modified_dontauditxperms = None self.added_type_transitions = None self.removed_type_transitions = None self.modified_type_transitions = None self.added_type_changes = None self.removed_type_changes = None self.modified_type_changes = None self.added_type_members = None self.removed_type_members = None self.modified_type_members = None # Sets of rules for each policy self._left_te_rules.clear() self._right_te_rules.clear() class AVRuleWrapper(Wrapper): """Wrap access vector rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass", "conditional", "conditional_block") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.tclass = SymbolWrapper(rule.tclass) self.key = hash(rule) try: self.conditional = ConditionalExprWrapper(rule.conditional) self.conditional_block = rule.conditional_block except RuleNotConditional: self.conditional = None self.conditional_block = None def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because TERuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass and \ self.conditional == other.conditional and \ self.conditional_block == other.conditional_block class AVRuleXpermWrapper(Wrapper): """Wrap extended permission access vector rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass", "xperm_type") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.tclass = SymbolWrapper(rule.tclass) self.xperm_type = rule.xperm_type self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because TERuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass and \ self.xperm_type == other.xperm_type class TERuleWrapper(Wrapper): """Wrap type_* rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass", "conditional", "conditional_block", "filename") def __init__(self, rule): self.origin = rule self.ruletype = rule.ruletype self.source = SymbolWrapper(rule.source) self.target = SymbolWrapper(rule.target) self.tclass = SymbolWrapper(rule.tclass) self.key = hash(rule) try: self.conditional = ConditionalExprWrapper(rule.conditional) self.conditional_block = rule.conditional_block except RuleNotConditional: self.conditional = None self.conditional_block = None try: self.filename = rule.filename except (RuleUseError, TERuleNoFilename): self.filename = None def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because TERuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass and \ self.conditional == other.conditional and \ self.conditional_block == other.conditional_block and \ self.filename == self.filename setools-4.1.1/setools/diff/typeattr.py000066400000000000000000000055141314142262400200370ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_typeattr_record = namedtuple("modified_typeattr", ["added_types", "removed_types", "matched_types"]) class TypeAttributesDifference(Difference): """Determine the difference in type attributes between two policies.""" added_type_attributes = DiffResultDescriptor("diff_type_attributes") removed_type_attributes = DiffResultDescriptor("diff_type_attributes") modified_type_attributes = DiffResultDescriptor("diff_type_attributes") def diff_type_attributes(self): """Generate the difference in type attributes between the policies.""" self.log.info( "Generating type attribute differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_type_attributes, self.removed_type_attributes, matched_attributes = \ self._set_diff( (SymbolWrapper(r) for r in self.left_policy.typeattributes()), (SymbolWrapper(r) for r in self.right_policy.typeattributes())) self.modified_type_attributes = dict() for left_attribute, right_attribute in matched_attributes: # Criteria for modified attributes # 1. change to type set added_types, removed_types, matched_types = self._set_diff( (SymbolWrapper(t) for t in left_attribute.expand()), (SymbolWrapper(t) for t in right_attribute.expand())) if added_types or removed_types: self.modified_type_attributes[left_attribute] = modified_typeattr_record( added_types, removed_types, matched_types) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting type attribute differences") self.added_type_attributes = None self.removed_type_attributes = None self.modified_type_attributes = None setools-4.1.1/setools/diff/types.py000066400000000000000000000077061314142262400173340ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper modified_types_record = namedtuple("modified_type", ["added_attributes", "removed_attributes", "matched_attributes", "modified_permissive", "permissive", "added_aliases", "removed_aliases", "matched_aliases"]) class TypesDifference(Difference): """Determine the difference in types between two policies.""" added_types = DiffResultDescriptor("diff_types") removed_types = DiffResultDescriptor("diff_types") modified_types = DiffResultDescriptor("diff_types") def diff_types(self): """Generate the difference in types between the policies.""" self.log.info( "Generating type differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_types, self.removed_types, matched_types = self._set_diff( (SymbolWrapper(t) for t in self.left_policy.types()), (SymbolWrapper(t) for t in self.right_policy.types())) self.modified_types = dict() for left_type, right_type in matched_types: # Criteria for modified types # 1. change to attribute set, or # 2. change to alias set, or # 3. different permissive setting added_attr, removed_attr, matched_attr = self._set_diff( (SymbolWrapper(a) for a in left_type.attributes()), (SymbolWrapper(a) for a in right_type.attributes())) added_aliases, removed_aliases, matched_aliases = self._set_diff(left_type.aliases(), right_type.aliases()) left_permissive = left_type.ispermissive right_permissive = right_type.ispermissive mod_permissive = left_permissive != right_permissive if added_attr or removed_attr or added_aliases or removed_aliases or mod_permissive: self.modified_types[left_type] = modified_types_record(added_attr, removed_attr, matched_attr, mod_permissive, left_permissive, added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting type differences") self.added_types = None self.removed_types = None self.modified_types = None setools-4.1.1/setools/diff/users.py000066400000000000000000000116531314142262400173250ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from ..policyrep.exception import MLSDisabled from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .mls import LevelWrapper, RangeWrapper modified_users_record = namedtuple("modified_user", ["added_roles", "removed_roles", "matched_roles", "added_level", "removed_level", "added_range", "removed_range"]) class UsersDifference(Difference): """Determine the difference in users between two policies.""" added_users = DiffResultDescriptor("diff_users") removed_users = DiffResultDescriptor("diff_users") modified_users = DiffResultDescriptor("diff_users") def diff_users(self): """Generate the difference in users between the policies.""" self.log.info( "Generating user differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_users, self.removed_users, matched_users = self._set_diff( (SymbolWrapper(r) for r in self.left_policy.users()), (SymbolWrapper(r) for r in self.right_policy.users())) self.modified_users = dict() for left_user, right_user in matched_users: # Criteria for modified users # 1. change to role set, or # 2. change to default level, or # 3. change to range added_roles, removed_roles, matched_roles = self._set_diff( (SymbolWrapper(r) for r in left_user.roles), (SymbolWrapper(r) for r in right_user.roles)) # keep wrapped and unwrapped MLS objects here so there # are not several nested try blocks try: left_level_wrap = LevelWrapper(left_user.mls_level) left_range_wrap = RangeWrapper(left_user.mls_range) left_level = left_user.mls_level left_range = left_user.mls_range except MLSDisabled: left_level_wrap = None left_range_wrap = None left_level = "None (MLS Disabled)" left_range = "None (MLS Disabled)" try: right_level_wrap = LevelWrapper(right_user.mls_level) right_range_wrap = RangeWrapper(right_user.mls_range) right_level = right_user.mls_level right_range = right_user.mls_range except MLSDisabled: right_level_wrap = None right_range_wrap = None right_level = "None (MLS Disabled)" right_range = "None (MLS Disabled)" if left_level_wrap != right_level_wrap: added_level = right_level removed_level = left_level else: added_level = None removed_level = None if left_range_wrap != right_range_wrap: added_range = right_range removed_range = left_range else: added_range = None removed_range = None if added_roles or removed_roles or removed_level or removed_range: self.modified_users[left_user] = modified_users_record(added_roles, removed_roles, matched_roles, added_level, removed_level, added_range, removed_range) # # Internal functions # def _reset_diff(self): """Reset diff results on policy changes.""" self.log.debug("Resetting user differences") self.added_users = None self.removed_users = None self.modified_users = None setools-4.1.1/setools/dta.py000066400000000000000000000530721314142262400160250ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=unsubscriptable-object import itertools import logging from collections import defaultdict, namedtuple import networkx as nx from networkx.exception import NetworkXError, NetworkXNoPath from .descriptors import EdgeAttrDict, EdgeAttrList from .policyrep import TERuletype __all__ = ['DomainTransitionAnalysis'] # Return values for the analysis # are in the following tuple formats: step_output = namedtuple("step", ["source", "target", "transition", "entrypoints", "setexec", "dyntransition", "setcurrent"]) entrypoint_output = namedtuple("entrypoints", ["name", "entrypoint", "execute", "type_transition"]) class DomainTransitionAnalysis(object): """Domain transition analysis.""" def __init__(self, policy, reverse=False, exclude=None): """ Parameter: policy The policy to analyze. """ self.log = logging.getLogger(__name__) self.policy = policy self.exclude = exclude self.reverse = reverse self.rebuildgraph = True self.rebuildsubgraph = True self.G = nx.DiGraph() self.subG = None @property def reverse(self): return self._reverse @reverse.setter def reverse(self, direction): self._reverse = bool(direction) self.rebuildsubgraph = True @property def exclude(self): return self._exclude @exclude.setter def exclude(self, types): if types: self._exclude = [self.policy.lookup_type(t) for t in types] else: self._exclude = [] self.rebuildsubgraph = True def shortest_path(self, source, target): """ Generator which yields one shortest domain transition path between the source and target types (there may be more). Parameters: source The source type. target The target type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating one domain transition path from {0} to {1}...".format(s, t)) try: yield self.__generate_steps(nx.shortest_path(self.subG, s, t)) except (NetworkXNoPath, NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph pass def all_paths(self, source, target, maxlen=2): """ Generator which yields all domain transition paths between the source and target up to the specified maximum path length. Parameters: source The source type. target The target type. maxlen Maximum length of paths. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ if maxlen < 1: raise ValueError("Maximum path length must be positive.") s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all domain transition paths from {0} to {1}, max length {2}...". format(s, t, maxlen)) try: for path in nx.all_simple_paths(self.subG, s, t, maxlen): yield self.__generate_steps(path) except (NetworkXNoPath, NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph pass def all_shortest_paths(self, source, target): """ Generator which yields all shortest domain transition paths between the source and target types. Parameters: source The source type. target The target type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all shortest domain transition paths from {0} to {1}...". format(s, t)) try: for path in nx.all_shortest_paths(self.subG, s, t): yield self.__generate_steps(path) except (NetworkXNoPath, NetworkXError, KeyError): # NetworkXError: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph # KeyError: work around NetworkX bug # when the source node is not in the graph pass def transitions(self, type_): """ Generator which yields all domain transitions out of a specified source type. Parameters: type_ The starting type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s = self.policy.lookup_type(type_) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all domain transitions {1} {0}". format(s, "in to" if self.reverse else "out from")) try: for source, target in self.subG.out_edges_iter(s): edge = Edge(self.subG, source, target) if self.reverse: real_source, real_target = target, source else: real_source, real_target = source, target yield step_output(real_source, real_target, edge.transition, self.__generate_entrypoints(edge), edge.setexec, edge.dyntransition, edge.setcurrent) except NetworkXError: # NetworkXError: the type is valid but not in graph, e.g. excluded pass def get_stats(self): # pragma: no cover """ Get the domain transition graph statistics. Return: str """ if self.rebuildgraph: self._build_graph() return nx.info(self.G) # # Internal functions follow # @staticmethod def __generate_entrypoints(edge): """ Creates a list of entrypoint, execute, and type_transition rules for each entrypoint. Parameter: data The dictionary of entrypoints. Return: list of tuple(type, entry, exec, trans) type The entrypoint type. entry The list of entrypoint rules. exec The list of execute rules. trans The list of type_transition rules. """ return [entrypoint_output(e, edge.entrypoint[e], edge.execute[e], edge.type_transition[e]) for e in edge.entrypoint] def __generate_steps(self, path): """ Generator which yields the source, target, and associated rules for each domain transition. Parameter: path A list of graph node names representing an information flow path. Yield: tuple(source, target, transition, entrypoints, setexec, dyntransition, setcurrent) source The source type for this step of the domain transition. target The target type for this step of the domain transition. transition The list of transition rules. entrypoints Generator which yields entrypoint-related rules. setexec The list of setexec rules. dyntranstion The list of dynamic transition rules. setcurrent The list of setcurrent rules. """ for s in range(1, len(path)): source = path[s - 1] target = path[s] edge = Edge(self.subG, source, target) # Yield the actual source and target. # The above perspective is reversed # if the graph has been reversed. if self.reverse: real_source, real_target = target, source else: real_source, real_target = source, target yield step_output(real_source, real_target, edge.transition, self.__generate_entrypoints(edge), edge.setexec, edge.dyntransition, edge.setcurrent) # # Graph building functions # # Domain transition requirements: # # Standard transitions a->b: # allow a b:process transition; # allow a b_exec:file execute; # allow b b_exec:file entrypoint; # # and at least one of: # allow a self:process setexec; # type_transition a b_exec:process b; # # Dynamic transition x->y: # allow x y:process dyntransition; # allow x self:process setcurrent; # # Algorithm summary: # 1. iterate over all rules # 1. skip non allow/type_transition rules # 2. if process transition or dyntransition, create edge, # initialize rule lists, add the (dyn)transition rule # 3. if process setexec or setcurrent, add to appropriate dict # keyed on the subject # 4. if file exec, entrypoint, or type_transition:process, # add to appropriate dict keyed on subject,object. # 2. Iterate over all graph edges: # 1. if there is a transition rule (else add to invalid # transition list): # 1. use set intersection to find matching exec # and entrypoint rules. If none, add to invalid # transition list. # 2. for each valid entrypoint, add rules to the # edge's lists if there is either a # type_transition for it or the source process # has setexec permissions. # 3. If there are neither type_transitions nor # setexec permissions, add to the invalid # transition list # 2. if there is a dyntransition rule (else add to invalid # dyntrans list): # 1. If the source has a setcurrent rule, add it # to the edge's list, else add to invalid # dyntransition list. # 3. Iterate over all graph edges: # 1. if the edge has an invalid trans and dyntrans, delete # the edge. # 2. if the edge has an invalid trans, clear the related # lists on the edge. # 3. if the edge has an invalid dyntrans, clear the related # lists on the edge. # def _build_graph(self): self.G.clear() self.G.name = "Domain transition graph for {0}.".format(self.policy) self.log.info("Building domain transition graph from {0}...".format(self.policy)) # hash tables keyed on domain type setexec = defaultdict(list) setcurrent = defaultdict(list) # hash tables keyed on (domain, entrypoint file type) # the parameter for defaultdict has to be callable # hence the lambda for the nested defaultdict execute = defaultdict(lambda: defaultdict(list)) entrypoint = defaultdict(lambda: defaultdict(list)) # hash table keyed on (domain, entrypoint, target domain) type_trans = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) for rule in self.policy.terules(): if rule.ruletype == TERuletype.allow: if rule.tclass not in ["process", "file"]: continue perms = rule.perms if rule.tclass == "process": if "transition" in perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add edges if they actually # transition to a new type if s != t: edge = Edge(self.G, s, t, create=True) edge.transition.append(rule) if "dyntransition" in perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add edges if they actually # transition to a new type if s != t: e = Edge(self.G, s, t, create=True) e.dyntransition.append(rule) if "setexec" in perms: for s in rule.source.expand(): setexec[s].append(rule) if "setcurrent" in perms: for s in rule.source.expand(): setcurrent[s].append(rule) else: if "execute" in perms: for s, t in itertools.product( rule.source.expand(), rule.target.expand()): execute[s][t].append(rule) if "entrypoint" in perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): entrypoint[s][t].append(rule) elif rule.ruletype == TERuletype.type_transition: if rule.tclass != "process": continue d = rule.default for s, t in itertools.product(rule.source.expand(), rule.target.expand()): type_trans[s][t][d].append(rule) invalid_edge = [] clear_transition = [] clear_dyntransition = [] for s, t in self.G.edges_iter(): edge = Edge(self.G, s, t) invalid_trans = False invalid_dyntrans = False if edge.transition: # get matching domain exec w/entrypoint type entry = set(entrypoint[t].keys()) exe = set(execute[s].keys()) match = entry.intersection(exe) if not match: # there are no valid entrypoints invalid_trans = True else: # TODO try to improve the # efficiency in this loop for m in match: if s in setexec or type_trans[s][m]: # add key for each entrypoint edge.entrypoint[m] += entrypoint[t][m] edge.execute[m] += execute[s][m] if type_trans[s][m][t]: edge.type_transition[m] += type_trans[s][m][t] if s in setexec: edge.setexec.extend(setexec[s]) if not edge.setexec and not edge.type_transition: invalid_trans = True else: invalid_trans = True if edge.dyntransition: if s in setcurrent: edge.setcurrent.extend(setcurrent[s]) else: invalid_dyntrans = True else: invalid_dyntrans = True # cannot change the edges while iterating over them, # so keep appropriate lists if invalid_trans and invalid_dyntrans: invalid_edge.append(edge) elif invalid_trans: clear_transition.append(edge) elif invalid_dyntrans: clear_dyntransition.append(edge) # Remove invalid transitions self.G.remove_edges_from(invalid_edge) for edge in clear_transition: # if only the regular transition is invalid, # clear the relevant lists del edge.transition del edge.execute del edge.entrypoint del edge.type_transition del edge.setexec for edge in clear_dyntransition: # if only the dynamic transition is invalid, # clear the relevant lists del edge.dyntransition del edge.setcurrent self.rebuildgraph = False self.rebuildsubgraph = True self.log.info("Completed building domain transition graph.") self.log.debug("Graph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.G), nx.number_of_edges(self.G))) def __remove_excluded_entrypoints(self): invalid_edges = [] for source, target in self.subG.edges_iter(): edge = Edge(self.subG, source, target) entrypoints = set(edge.entrypoint) entrypoints.intersection_update(self.exclude) if not entrypoints: # short circuit if there are no # excluded entrypoint types on # this edge. continue for e in entrypoints: # clear the entrypoint data del edge.entrypoint[e] del edge.execute[e] try: del edge.type_transition[e] except KeyError: # setexec pass # cannot delete the edges while iterating over them if not edge.entrypoint and not edge.dyntransition: invalid_edges.append(edge) self.subG.remove_edges_from(invalid_edges) def _build_subgraph(self): if self.rebuildgraph: self._build_graph() self.log.info("Building domain transition subgraph.") self.log.debug("Excluding {0}".format(self.exclude)) self.log.debug("Reverse {0}".format(self.reverse)) # reverse graph for reverse DTA if self.reverse: self.subG = self.G.reverse(copy=True) else: self.subG = self.G.copy() if self.exclude: # delete excluded domains from subgraph self.subG.remove_nodes_from(self.exclude) # delete excluded entrypoints from subgraph self.__remove_excluded_entrypoints() self.rebuildsubgraph = False self.log.info("Completed building domain transition subgraph.") self.log.debug("Subgraph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.subG), nx.number_of_edges(self.subG))) class Edge(object): """ A graph edge. Also used for returning domain transition steps. Parameters: graph The NetworkX graph. source The source type of the edge. target The target tyep of the edge. Keyword Parameters: create (T/F) create the edge if it does not exist. The default is False. """ transition = EdgeAttrList('transition') setexec = EdgeAttrList('setexec') dyntransition = EdgeAttrList('dyntransition') setcurrent = EdgeAttrList('setcurrent') entrypoint = EdgeAttrDict('entrypoint') execute = EdgeAttrDict('execute') type_transition = EdgeAttrDict('type_transition') def __init__(self, graph, source, target, create=False): self.G = graph self.source = source self.target = target if not self.G.has_edge(source, target): if not create: raise ValueError("Edge does not exist in graph") else: self.G.add_edge(source, target) self.transition = None self.entrypoint = None self.execute = None self.type_transition = None self.setexec = None self.dyntransition = None self.setcurrent = None def __getitem__(self, key): # This is implemented so this object can be used in NetworkX # functions that operate on (source, target) tuples if isinstance(key, slice): return [self._index_to_item(i) for i in range(* key.indices(2))] else: return self._index_to_item(key) def _index_to_item(self, index): """Return source or target based on index.""" if index == 0: return self.source elif index == 1: return self.target else: raise IndexError("Invalid index (edges only have 2 items): {0}".format(index)) setools-4.1.1/setools/exception.py000066400000000000000000000027131314142262400172470ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Base class for exceptions # class SEToolsException(Exception): """Base class for all SETools exceptions.""" pass # # Permission map exceptions # class PermissionMapException(SEToolsException): """Base class for all permission map exceptions.""" pass class PermissionMapParseError(PermissionMapException): """Exception for parse errors while reading permission map files.""" pass class RuleTypeError(PermissionMapException): """Exception for using rules with incorrect rule type.""" pass class UnmappedClass(PermissionMapException): """Exception for classes that are unmapped""" pass class UnmappedPermission(PermissionMapException): """Exception for permissions that are unmapped""" pass setools-4.1.1/setools/fsusequery.py000066400000000000000000000065551314142262400174740ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchContext from .policyrep import FSUseRuletype from .query import PolicyQuery from .util import match_regex class FSUseQuery(MatchContext, PolicyQuery): """ Query fs_use_* statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. fs The criteria to match the file system type. fs_regex If true, regular expression matching will be used on the file system type. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ ruletype = CriteriaSetDescriptor(enum_class=FSUseRuletype) fs = CriteriaDescriptor("fs_regex") fs_regex = False def __init__(self, policy, **kwargs): super(FSUseQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching fs_use_* statements.""" self.log.info("Generating fs_use_* results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) self._match_context_debug(self.log) for fsu in self.policy.fs_uses(): if self.ruletype and fsu.ruletype not in self.ruletype: continue if self.fs and not match_regex( fsu.fs, self.fs, self.fs_regex): continue if not self._match_context(fsu.context): continue yield fsu setools-4.1.1/setools/genfsconquery.py000066400000000000000000000072721314142262400201460ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor from .mixins import MatchContext from .query import PolicyQuery from .util import match_regex class GenfsconQuery(MatchContext, PolicyQuery): """ Query genfscon statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: fs The criteria to match the file system type. fs_regex If true, regular expression matching will be used on the file system type. path The criteria to match the path. path_regex If true, regular expression matching will be used on the path. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ filetype = None fs = CriteriaDescriptor("fs_regex") fs_regex = False path = CriteriaDescriptor("path_regex") path_regex = False def __init__(self, policy, **kwargs): super(GenfsconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching genfscons.""" self.log.info("Generating genfscon results from {0.policy}".format(self)) self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) self.log.debug("Path: {0.path!r}, regex: {0.path_regex}".format(self)) self.log.debug("Filetype: {0.filetype!r}".format(self)) self._match_context_debug(self.log) for genfs in self.policy.genfscons(): if self.fs and not match_regex( genfs.fs, self.fs, self.fs_regex): continue if self.path and not match_regex( genfs.path, self.path, self.path_regex): continue if self.filetype and not self.filetype == genfs.filetype: continue if not self._match_context(genfs.context): continue yield genfs setools-4.1.1/setools/infoflow.py000066400000000000000000000330641314142262400170770ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import itertools import logging import networkx as nx from networkx.exception import NetworkXError, NetworkXNoPath from .descriptors import EdgeAttrIntMax, EdgeAttrList from .policyrep import TERuletype __all__ = ['InfoFlowAnalysis'] class InfoFlowAnalysis(object): """Information flow analysis.""" def __init__(self, policy, perm_map, min_weight=1, exclude=None): """ Parameters: policy The policy to analyze. perm_map The permission map or path to the permission map file. minweight The minimum permission weight to include in the analysis. (default is 1) exclude The types excluded from the information flow analysis. (default is none) """ self.log = logging.getLogger(__name__) self.policy = policy self.min_weight = min_weight self.perm_map = perm_map self.exclude = exclude self.rebuildgraph = True self.rebuildsubgraph = True self.G = nx.DiGraph() self.subG = None @property def min_weight(self): return self._min_weight @min_weight.setter def min_weight(self, weight): if not 1 <= weight <= 10: raise ValueError( "Min information flow weight must be an integer 1-10.") self._min_weight = weight self.rebuildsubgraph = True @property def perm_map(self): return self._perm_map @perm_map.setter def perm_map(self, perm_map): self._perm_map = perm_map self.rebuildgraph = True self.rebuildsubgraph = True @property def exclude(self): return self._exclude @exclude.setter def exclude(self, types): if types: self._exclude = [self.policy.lookup_type(t) for t in types] else: self._exclude = [] self.rebuildsubgraph = True def shortest_path(self, source, target): """ Generator which yields one shortest path between the source and target types (there may be more). Parameters: source The source type. target The target type. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating one shortest information flow path from {0} to {1}...". format(s, t)) try: yield self.__generate_steps(nx.shortest_path(self.subG, s, t)) except (NetworkXNoPath, NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph pass def all_paths(self, source, target, maxlen=2): """ Generator which yields all paths between the source and target up to the specified maximum path length. This algorithm tends to get very expensive above 3-5 steps, depending on the policy complexity. Parameters: source The source type. target The target type. maxlen Maximum length of paths. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ if maxlen < 1: raise ValueError("Maximum path length must be positive.") s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all information flow paths from {0} to {1}, max length {2}...". format(s, t, maxlen)) try: for path in nx.all_simple_paths(self.subG, s, t, maxlen): yield self.__generate_steps(path) except (NetworkXNoPath, NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph pass def all_shortest_paths(self, source, target): """ Generator which yields all shortest paths between the source and target types. Parameters: source The source type. target The target type. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all shortest information flow paths from {0} to {1}...". format(s, t)) try: for path in nx.all_shortest_paths(self.subG, s, t): yield self.__generate_steps(path) except (NetworkXNoPath, NetworkXError, KeyError): # NetworkXError: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph # KeyError: work around NetworkX bug # when the source node is not in the graph pass def infoflows(self, type_, out=True): """ Generator which yields all information flows in/out of a specified source type. Parameters: source The starting type. Keyword Parameters: out If true, information flows out of the type will be returned. If false, information flows in to the type will be returned. Default is true. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each information flow. """ s = self.policy.lookup_type(type_) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all information flows {0} {1}". format("out of" if out else "into", s)) if out: flows = self.subG.out_edges_iter(s) else: flows = self.subG.in_edges_iter(s) try: for source, target in flows: yield Edge(self.subG, source, target) except NetworkXError: # NetworkXError: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight pass def get_stats(self): # pragma: no cover """ Get the information flow graph statistics. Return: str """ if self.rebuildgraph: self._build_graph() return nx.info(self.G) # # Internal functions follow # def __generate_steps(self, path): """ Generator which returns the source, target, and associated rules for each information flow step. Parameter: path A list of graph node names representing an information flow path. Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ for s in range(1, len(path)): yield Edge(self.subG, path[s - 1], path[s]) # # # Graph building functions # # # 1. _build_graph determines the flow in each direction for each TE # rule and then expands the rule. All information flows are # included in this main graph: memory is traded off for efficiency # as the main graph should only need to be rebuilt if permission # weights change. # 2. _build_subgraph derives a subgraph which removes all excluded # types (nodes) and edges (information flows) which are below the # minimum weight. This subgraph is rebuilt only if the main graph # is rebuilt or the minimum weight or excluded types change. def _build_graph(self): self.G.clear() self.G.name = "Information flow graph for {0}.".format(self.policy) self.perm_map.map_policy(self.policy) self.log.info("Building information flow graph from {0}...".format(self.policy)) for rule in self.policy.terules(): if rule.ruletype != TERuletype.allow: continue (rweight, wweight) = self.perm_map.rule_weight(rule) for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add flows if they actually flow # in or out of the source type type if s != t: if wweight: edge = Edge(self.G, s, t, create=True) edge.rules.append(rule) edge.weight = wweight if rweight: edge = Edge(self.G, t, s, create=True) edge.rules.append(rule) edge.weight = rweight self.rebuildgraph = False self.rebuildsubgraph = True self.log.info("Completed building information flow graph.") self.log.debug("Graph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.G), nx.number_of_edges(self.G))) def _build_subgraph(self): if self.rebuildgraph: self._build_graph() self.log.info("Building information flow subgraph...") self.log.debug("Excluding {0!r}".format(self.exclude)) self.log.debug("Min weight {0}".format(self.min_weight)) # delete excluded types from subgraph nodes = [n for n in self.G.nodes() if n not in self.exclude] self.subG = self.G.subgraph(nodes) # delete edges below minimum weight. # no need if weight is 1, since that # does not exclude any edges. if self.min_weight > 1: delete_list = [] for s, t in self.subG.edges_iter(): edge = Edge(self.subG, s, t) if edge.weight < self.min_weight: delete_list.append(edge) self.subG.remove_edges_from(delete_list) self.rebuildsubgraph = False self.log.info("Completed building information flow subgraph.") self.log.debug("Subgraph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.subG), nx.number_of_edges(self.subG))) class Edge(object): """ A graph edge. Also used for returning information flow steps. Parameters: graph The NetworkX graph. source The source type of the edge. target The target type of the edge. Keyword Parameters: create (T/F) create the edge if it does not exist. The default is False. """ rules = EdgeAttrList('rules') # use capacity to store the info flow weight so # we can use network flow algorithms naturally. # The weight for each edge is 1 since each info # flow step is no more costly than another # (see below add_edge() call) weight = EdgeAttrIntMax('capacity') def __init__(self, graph, source, target, create=False): self.G = graph self.source = source self.target = target if not self.G.has_edge(source, target): if create: self.G.add_edge(source, target, weight=1) self.rules = None self.weight = None else: raise ValueError("Edge does not exist in graph") def __getitem__(self, key): # This is implemented so this object can be used in NetworkX # functions that operate on (source, target) tuples if isinstance(key, slice): return [self._index_to_item(i) for i in range(* key.indices(2))] else: return self._index_to_item(key) def _index_to_item(self, index): """Return source or target based on index.""" if index == 0: return self.source elif index == 1: return self.target else: raise IndexError("Invalid index (edges only have 2 items): {0}".format(index)) setools-4.1.1/setools/initsidquery.py000066400000000000000000000054541314142262400200070ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext, MatchName from .query import PolicyQuery class InitialSIDQuery(MatchName, MatchContext, PolicyQuery): """ Initial SID (Initial context) query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The Initial SID name to match. name_regex If true, regular expression matching will be used on the Initial SID name. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ def __init__(self, policy, **kwargs): super(InitialSIDQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching initial SIDs.""" self.log.info("Generating initial SID results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_context_debug(self.log) for i in self.policy.initialsids(): if not self._match_name(i): continue if not self._match_context(i.context): continue yield i setools-4.1.1/setools/iomemconquery.py000066400000000000000000000107131314142262400201440ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext from .policyrep.xencontext import IomemconRange from .query import PolicyQuery from .util import match_range class IomemconQuery(MatchContext, PolicyQuery): """ Iomemcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: addr A 2-tuple of the memory addr range to match. (Set both to the same value for a single mem addr) addr_subset If true, the criteria will match if it is a subset of the iomemcon's range. addr_overlap If true, the criteria will match if it overlaps any of the iomemcon's range. addr_superset If true, the criteria will match if it is a superset of the iomemcon's range. addr_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _addr = None addr_subset = False addr_overlap = False addr_superset = False addr_proper = False @property def addr(self): return self._addr @addr.setter def addr(self, value): pending_addr = IomemconRange(*value) if all(pending_addr): if pending_addr.low < 1 or pending_addr.high < 1: raise ValueError("Memory address must be positive: {0.low}-{0.high}". format(pending_addr)) if pending_addr.low > pending_addr.high: raise ValueError( "The low mem addr must be smaller than the high mem addr: {0.low}-{0.high}". format(pending_addr)) self._addr = pending_addr else: self._addr = None def __init__(self, policy, **kwargs): super(IomemconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching iomemcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Address: {0.addr!r}, overlap: {0.addr_overlap}, " "subset: {0.addr_subset}, superset: {0.addr_superset}, " "proper: {0.addr_proper}".format(self)) self._match_context_debug(self.log) for iomemcon in self.policy.iomemcons(): if self.addr and not match_range( iomemcon.addr, self.addr, self.addr_subset, self.addr_overlap, self.addr_superset, self.addr_proper): continue if not self._match_context(iomemcon.context): continue yield iomemcon setools-4.1.1/setools/ioportconquery.py000066400000000000000000000107271314142262400203570ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext from .policyrep import IoportconRange from .query import PolicyQuery from .util import match_range class IoportconQuery(MatchContext, PolicyQuery): """ Ioportcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ports A 2-tuple of the port range to match. (Set both to the same value for a single port) ports_subset If true, the criteria will match if it is a subset of the ioportcon's range. ports_overlap If true, the criteria will match if it overlaps any of the ioportcon's range. ports_superset If true, the criteria will match if it is a superset of the ioportcon's range. ports_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _ports = None ports_subset = False ports_overlap = False ports_superset = False ports_proper = False @property def ports(self): return self._ports @ports.setter def ports(self, value): pending_ports = IoportconRange(*value) if all(pending_ports): if pending_ports.low < 1 or pending_ports.high < 1: raise ValueError("Port numbers must be positive: {0.low}-{0.high}". format(pending_ports)) if pending_ports.low > pending_ports.high: raise ValueError( "The low port must be smaller than the high port: {0.low}-{0.high}". format(pending_ports)) self._ports = pending_ports else: self._ports = None def __init__(self, policy, **kwargs): super(IoportconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching ioportcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Ports: {0.ports!r}, overlap: {0.ports_overlap}, " "subset: {0.ports_subset}, superset: {0.ports_superset}, " "proper: {0.ports_proper}".format(self)) self._match_context_debug(self.log) for ioportcon in self.policy.ioportcons(): if self.ports and not match_range( ioportcon.ports, self.ports, self.ports_subset, self.ports_overlap, self.ports_superset, self.ports_proper): continue if not self._match_context(ioportcon.context): continue yield ioportcon setools-4.1.1/setools/mixins.py000066400000000000000000000155761314142262400165730ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=attribute-defined-outside-init,no-member import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .util import match_in_set, match_regex, match_range, match_regex_or_set class MatchAlias(object): """Mixin for matching an object's aliases.""" alias = CriteriaDescriptor("alias_regex") alias_regex = False def _match_alias_debug(self, log): """Emit log debugging info for alias matching.""" log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self)) def _match_alias(self, obj): """ Match the alias criteria Parameter: obj An object with an alias generator method named "aliases" """ if not self.alias: # if there is no criteria, everything matches. return True return match_in_set(obj.aliases(), self.alias, self.alias_regex) class MatchContext(object): """ Mixin for matching contexts. Class attributes: user The user to match in the context. user_regex If true, regular expression matching will be used on the user. role The role to match in the context. role_regex If true, regular expression matching will be used on the role. type_ The type to match in the context. type_regex If true, regular expression matching will be used on the type. range_ The range to match in the context. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset on range matching operations. No effect if not using set operations. """ user = CriteriaDescriptor("user_regex", "lookup_user") user_regex = False role = CriteriaDescriptor("role_regex", "lookup_role") role_regex = False type_ = CriteriaDescriptor("type_regex", "lookup_type") type_regex = False range_ = CriteriaDescriptor(lookup_function="lookup_range") range_overlap = False range_subset = False range_superset = False range_proper = False def _match_context_debug(self, log): """Emit log debugging info for context matching.""" log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) def _match_context(self, context): """ Match the context criteria. Parameter: obj An object with context attributes "user", "role", "type_" and "range_". """ if self.user and not match_regex( context.user, self.user, self.user_regex): return False if self.role and not match_regex( context.role, self.role, self.role_regex): return False if self.type_ and not match_regex( context.type_, self.type_, self.type_regex): return False if self.range_ and not match_range( context.range_, self.range_, self.range_subset, self.range_overlap, self.range_superset, self.range_proper): return False return True class MatchName(object): """Mixin for matching an object's name.""" name = CriteriaDescriptor("name_regex") name_regex = False def _match_name_debug(self, log): """Log debugging messages for name matching.""" log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) def _match_name(self, obj): """Match the object to the name criteria.""" if not self.name: # if there is no criteria, everything matches. return True return match_regex(obj, self.name, self.name_regex) class MatchObjClass(object): """Mixin for matching an object's class.""" tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex = False def _match_object_class_debug(self, log): """Emit log debugging info for permission matching.""" log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) def _match_object_class(self, obj): """ Match the object class criteria Parameter: obj An object with an object class attribute named "tclass" """ if not self.tclass: # if there is no criteria, everything matches. return True elif self.tclass_regex: return bool(self.tclass.search(str(obj.tclass))) else: return obj.tclass in self.tclass class MatchPermission(object): """Mixin for matching an object's permissions.""" perms = CriteriaSetDescriptor("perms_regex") perms_equal = False perms_regex = False perms_subset = False def _match_perms_debug(self, log): """Emit log debugging info for permission matching.""" log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}, " "subset: {0.perms_subset!r}".format(self)) def _match_perms(self, obj): """ Match the permission criteria Parameter: obj An object with a permission set class attribute named "perms" """ if not self.perms: # if there is no criteria, everything matches. return True if self.perms_subset: return obj.perms >= self.perms else: return match_regex_or_set(obj.perms, self.perms, self.perms_equal, self.perms_regex) setools-4.1.1/setools/mlsrulequery.py000066400000000000000000000111371314142262400200220ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchObjClass from .policyrep import MLSRuletype from .query import PolicyQuery from .util import match_indirect_regex, match_range class MLSRuleQuery(MatchObjClass, PolicyQuery): """ Query MLS rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source type/attribute to match. source_regex If true, regular expression matching will be used on the source type/attribute. target The name of the target type/attribute to match. target_regex If true, regular expression matching will be used on the target type/attribute. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. """ ruletype = CriteriaSetDescriptor(enum_class=MLSRuletype) source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") source_regex = False source_indirect = True target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") target_regex = False target_indirect = True tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex = False default = CriteriaDescriptor(lookup_function="lookup_range") default_overlap = False default_subset = False default_superset = False default_proper = False def __init__(self, policy, **kwargs): super(MLSRuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching MLS rules.""" self.log.info("Generating MLS rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}, overlap: {0.default_overlap}, " "subset: {0.default_subset}, superset: {0.default_superset}, " "proper: {0.default_proper}".format(self)) for rule in self.policy.mlsrules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source type # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # if not self._match_object_class(rule): continue # # Matching on range # if self.default and not match_range( rule.default, self.default, self.default_subset, self.default_overlap, self.default_superset, self.default_proper): continue # if we get here, we have matched all available criteria yield rule setools-4.1.1/setools/netifconquery.py000066400000000000000000000056731314142262400201540ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext, MatchName from .query import PolicyQuery from .util import match_regex class NetifconQuery(MatchContext, MatchName, PolicyQuery): """ Network interface context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the network interface to match. name_regex If true, regular expression matching will be used for matching the name. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ def __init__(self, policy, **kwargs): super(NetifconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching netifcons.""" self.log.info("Generating netifcon results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_context_debug(self.log) for netif in self.policy.netifcons(): if self.name and not match_regex( netif.netif, self.name, self.name_regex): continue if not self._match_context(netif.context): continue yield netif setools-4.1.1/setools/nodeconquery.py000066400000000000000000000124311314142262400177620ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # try: import ipaddress except ImportError: # pragma: no cover pass import logging from socket import AF_INET, AF_INET6 from .mixins import MatchContext from .policyrep import NodeconIPVersion from .query import PolicyQuery class NodeconQuery(MatchContext, PolicyQuery): """ Query nodecon statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: network The IPv4/IPv6 address or IPv4/IPv6 network address with netmask, e.g. 192.168.1.0/255.255.255.0 or "192.168.1.0/24". network_overlap If true, the net will match if it overlaps with the nodecon's network instead of equality. ip_version The IP version of the nodecon to match. (socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6) user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _network = None network_overlap = False _ip_version = None @property def ip_version(self): return self._ip_version @ip_version.setter def ip_version(self, value): if value: self._ip_version = NodeconIPVersion.lookup(value) else: self._ip_version = None @property def network(self): return self._network @network.setter def network(self, value): if value: try: self._network = ipaddress.ip_network(value) except NameError: # pragma: no cover raise RuntimeError("Nodecon IP address/network functions require Python 3.3+.") else: self._network = None def __init__(self, policy, **kwargs): super(NodeconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching nodecons.""" self.log.info("Generating nodecon results from {0.policy}".format(self)) self.log.debug("Network: {0.network!r}, overlap: {0.network_overlap}".format(self)) self.log.debug("IP Version: {0.ip_version!r}".format(self)) self._match_context_debug(self.log) for nodecon in self.policy.nodecons(): if self.network: try: netmask = ipaddress.ip_address(nodecon.netmask) except NameError: # pragma: no cover # Should never actually hit this since the self.network # setter raises the same exception. raise RuntimeError("Nodecon IP address/network functions require Python 3.3+.") # Python 3.3's IPv6Network constructor does not support # expanded netmasks, only CIDR numbers. Convert netmask # into CIDR. # This is Brian Kernighan's method for counting set bits. # If the netmask happens to be invalid, this will # not detect it. CIDR = 0 int_netmask = int(netmask) while int_netmask: int_netmask &= int_netmask - 1 CIDR += 1 net = ipaddress.ip_network('{0}/{1}'.format(nodecon.address, CIDR)) if self.network_overlap: if not self.network.overlaps(net): continue else: if not net == self.network: continue if self.ip_version and self.ip_version != nodecon.ip_version: continue if not self._match_context(nodecon.context): continue yield nodecon setools-4.1.1/setools/objclassquery.py000066400000000000000000000074671314142262400201520ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchName from .policyrep.exception import NoCommon from .query import PolicyQuery from .util import match_regex, match_regex_or_set class ObjClassQuery(MatchName, PolicyQuery): """ Query object classes. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the object set to match. name_regex If true, regular expression matching will be used for matching the name. common The name of the inherited common to match. common_regex If true, regular expression matching will be used for matching the common name. perms The permissions to match. perms_equal If true, only commons with permission sets that are equal to the criteria will match. Otherwise, any intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. comparison will not be used. perms_indirect If false, permissions inherited from a common permission set not will be evaluated. Default is true. """ common = CriteriaDescriptor("common_regex", "lookup_common") common_regex = False perms = CriteriaSetDescriptor("perms_regex") perms_equal = False perms_indirect = True perms_regex = False def __init__(self, policy, **kwargs): super(ObjClassQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching object classes.""" self.log.info("Generating object class results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Common: {0.common!r}, regex: {0.common_regex}".format(self)) self.log.debug("Perms: {0.perms}, regex: {0.perms_regex}, " "eq: {0.perms_equal}, indirect: {0.perms_indirect}".format(self)) for class_ in self.policy.classes(): if not self._match_name(class_): continue if self.common: try: if not match_regex( class_.common, self.common, self.common_regex): continue except NoCommon: continue if self.perms: perms = class_.perms if self.perms_indirect: try: perms |= class_.common.perms except NoCommon: pass if not match_regex_or_set( perms, self.perms, self.perms_equal, self.perms_regex): continue yield class_ setools-4.1.1/setools/pcideviceconquery.py000066400000000000000000000060541314142262400207740ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext from .query import PolicyQuery class PcideviceconQuery(MatchContext, PolicyQuery): """ Pcidevicecon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: device A single PCI device ID. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _device = None @property def device(self): return self._device @device.setter def device(self, value): if value: if value < 1: raise ValueError("PCI device ID must be positive: {0}".format(value)) self._device = value else: self._device = None def __init__(self, policy, **kwargs): super(PcideviceconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching pcidevicecons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Device ID: {0.device!r}".format(self)) self._match_context_debug(self.log) for pcidevicecon in self.policy.pcidevicecons(): if self.device and self.device != pcidevicecon.device: continue if not self._match_context(pcidevicecon.context): continue yield pcidevicecon setools-4.1.1/setools/perm_map000066400000000000000000001613271314142262400164310ustar00rootroot00000000000000# This is a permission map file for use in policy analysis. This # file maps object permissions (read, getattr, setattr, ..., etc.) # for an object class, to exactly one of the following: read, write, # both, or none. This file may be edited as long as the specific # syntax rules are obeyed. # # For each object class, there is a set of object permissions that are # individually mapped to read, write, both, or none. If a new object # class is added, make sure that the current number of object classes # is increased. # # The syntax for an object class definition is: # class # # This is followed by each permission and its individual mapping to one # of the following: # # r = Read # w = Write # n = None # b = Both # # Additionally, you can choose to follow the mapping with an optional # permission weight value from 1 (less importance) to 10 (higher importance). # 10 is the default weight value if one is not provided. # # Look to the examples below for further clarification. # # Number of object classes. 95 class netlink_audit_socket 27 nlmsg_relay w 10 nlmsg_tty_audit w 10 nlmsg_readpriv r 10 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class tcp_socket 27 acceptfrom r 1 connectto w 1 node_bind n 1 newconn w 1 name_connect w 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class msgq 10 enqueue w 1 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class x_property 7 append w 10 create w 1 write w 10 destroy w 1 getattr r 7 setattr w 7 read r 10 class db_procedure 9 execute r 1 install w 10 entrypoint r 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class dir 25 rmdir b 1 audit_access r 1 remove_name w 1 add_name w 5 reparent w 1 execmod n 1 search r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class peer 1 recv r 10 class blk_file 20 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class chr_file 22 audit_access r 1 entrypoint r 1 execmod n 1 execute_no_trans r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class db_table 11 select n 1 delete w 1 update w 10 insert w 10 lock n 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class db_tuple 7 select n 1 delete w 1 update w 10 relabelfrom r 1 insert w 10 use r 10 relabelto w 1 class dbus 2 acquire_svc b 1 send_msg w 10 class ipc 9 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class lnk_file 20 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 1 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class process 30 getcap r 3 setcap w 1 sigstop w 1 sigchld w 1 share b 1 execheap n 1 setcurrent w 1 setfscreate w 1 setkeycreate w 1 siginh n 1 dyntransition w 10 transition w 5 fork n 1 getsession r 1 noatsecure n 1 sigkill w 1 signull n 1 setrlimit n 1 getattr r 1 getsched r 1 setexec w 1 setsched w 1 getpgid r 1 setpgid w 5 ptrace b 10 execstack n 1 rlimitinh n 1 setsockcreate w 1 signal w 5 execmem n 1 class capability2 6 mac_override n 1 mac_admin n 1 syslog n 1 block_suspend n 1 wake_alarm n 1 audit_read n 1 class fd 1 use b 1 class packet 7 forward_out w 10 flow_out w 10 send w 10 recv r 10 forward_in r 10 relabelto w 3 flow_in r 10 class socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class fifo_file 20 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class file 22 audit_access r 1 entrypoint r 1 execmod n 1 execute_no_trans r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class node 11 rawip_recv r 10 tcp_recv r 10 udp_recv r 10 rawip_send w 10 tcp_send w 10 udp_send w 10 dccp_recv r 10 dccp_send w 10 enforce_dest n 1 sendto w 10 recvfrom r 10 class x_cursor 7 create w 1 write w 10 destroy w 1 getattr r 7 setattr w 7 read r 10 use r 1 class x_server 6 record r 10 getattr r 7 grab w 1 setattr w 7 manage w 10 debug b 10 class db_view 7 expand w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr w 5 relabelto w 1 class netlink_nflog_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class key 7 create w 10 write w 10 view r 7 link w 7 setattr w 7 read r 10 search r 5 class netlink_tcpdiag_socket 24 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class unix_stream_socket 25 acceptfrom r 1 connectto w 1 newconn w 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_synthetic_event 2 send w 10 receive r 10 class db_database 11 access b 10 set_param w 7 load_module r 10 get_param r 7 install_module r 10 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class db_language 8 execute w 1 implement w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr w 5 relabelto w 1 class kernel_service 2 create_files_as n 1 use_as_override n 1 class netlink_route_socket 24 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_extension 2 use r 1 query r 5 class db_sequence 9 set_value w 10 get_value r 10 next_value w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr r 5 relabelto w 1 class shm 10 lock w 1 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class x_resource 2 write w 10 read r 10 class netlink_selinux_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class capability 32 setfcap n 1 setpcap n 1 fowner n 1 sys_boot n 1 sys_tty_config n 1 net_raw n 1 sys_admin n 1 sys_chroot n 1 sys_module n 1 sys_rawio n 1 dac_override n 1 ipc_owner n 1 kill n 1 dac_read_search n 1 sys_pacct n 1 net_broadcast n 1 net_bind_service n 1 sys_nice n 1 sys_time n 1 fsetid n 1 mknod n 1 setgid n 1 setuid n 1 lease n 1 net_admin n 1 audit_write n 1 linux_immutable n 1 sys_ptrace n 1 audit_control n 1 ipc_lock n 1 sys_resource n 1 chown n 1 class netlink_ip6fw_socket 24 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class dccp_socket 24 node_bind n 1 name_connect w 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_firewall_socket 24 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class sock_file 20 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 1 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 class unix_dgram_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_kobject_uevent_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class db_blob 10 write w 10 export r 10 import w 10 read r 10 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class filesystem 10 associate n 1 quotaget r 1 relabelfrom r 10 transition w 1 getattr r 1 quotamod w 1 mount w 1 remount w 1 unmount w 1 relabelto w 10 class netlink_xfrm_socket 24 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_device 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus r 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class db_schema 9 remove_name w 1 add_name w 5 search r 5 drop w 1 create w 1 relabelfrom w 1 getattr r 5 setattr w 5 relabelto r 1 class netlink_dnrt_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto r 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_client 4 destroy w 1 getattr r 7 setattr w 7 manage w 10 class x_gc 5 create w 1 destroy w 1 getattr r 7 setattr w 7 use r 1 class context 2 contains n 1 translate n 1 class nscd 10 shmemserv r 7 gethost r 7 getstat r 7 getgrp r 7 shmemhost r 7 shmempwd r 7 getpwd r 7 getserv r 7 shmemgrp r 7 admin w 5 class passwd 5 chfn w 5 crontab w 5 passwd w 1 chsh w 5 rootok n 1 class x_event 2 send w 10 receive r 10 class x_font 6 create w 1 destroy w 1 add_glyph w 1 remove_glyph w 1 getattr r 7 use r 1 class key_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netif 10 rawip_recv r 10 tcp_recv r 10 udp_recv r 10 rawip_send w 10 egress w 10 ingress r 10 tcp_send w 10 udp_send w 10 dccp_recv r 10 dccp_send w 10 class packet_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class memprotect 1 mmap_zero n 1 class msg 2 send w 10 receive r 10 class tun_socket 23 attach_queue w 5 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class udp_socket 23 node_bind n 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class appletalk_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 1 setattr w 1 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_colormap 10 add_color w 10 create w 1 write w 10 destroy w 1 install w 1 getattr r 7 read r 10 use r 1 remove_color w 10 uninstall w 1 class x_screen 8 show_cursor w 1 hide_cursor w 1 saver_show w 1 getattr r 7 setattr w 7 saver_hide w 1 saver_getattr r 7 saver_setattr w 7 class rawip_socket 23 node_bind n 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 1 setattr w 1 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_application_data 3 paste w 10 paste_after_confirm w 10 copy r 10 class association 4 setcontext w 3 sendto w 10 recvfrom r 10 polmatch r 1 class x_selection 4 write w 10 getattr r 7 setattr w 7 read r 10 class db_column 9 select r 10 update w 10 insert w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class netlink_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class x_drawable 19 get_property r 7 list_property r 7 set_property w 7 add_child w 1 override n 1 blend w 1 send w 10 create w 1 hide w 1 receive r 10 write w 10 show w 1 destroy w 1 list_child r 7 getattr r 7 setattr w 7 read r 10 manage w 10 remove_child w 1 class sem 9 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class system 13 module_request n 1 ipc_info n 1 syslog_read n 1 syslog_console n 1 syslog_mod n 1 reload w 1 halt n 1 reboot n 1 status r 5 enable n 1 disable n 1 start w 5 stop w 5 class x_keyboard 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus w 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class security 13 compute_member n 1 compute_user n 1 compute_create n 1 setenforce n 1 check_context n 1 setcheckreqprot n 1 compute_relabel n 1 setbool n 1 load_policy n 1 read_policy n 1 setsecparam n 1 compute_av n 1 validate_trans n 1 class x_pointer 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus w 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class binder 4 transfer w 3 call w 10 set_context_mgr w 1 impersonate n 1 class netlink_connector_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_netfilter_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_iscsi_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class db_exception 7 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 use r 1 class netlink_rdma_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_generic_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class netlink_scsitransport_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class service 6 status r 1 start w 1 disable n 1 enable n 1 reload w 1 stop w 1 class netlink_crypto_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class db_datatype 7 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 use r 1 class netlink_fib_lookup_socket 22 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 class cap_userns 32 setfcap n 1 setpcap n 1 fowner n 1 sys_boot n 1 sys_tty_config n 1 net_raw n 1 sys_admin n 1 sys_chroot n 1 sys_module n 1 sys_rawio n 1 dac_override n 1 ipc_owner n 1 kill n 1 dac_read_search n 1 sys_pacct n 1 net_broadcast n 1 net_bind_service n 1 sys_nice n 1 sys_time n 1 fsetid n 1 mknod n 1 setgid n 1 setuid n 1 lease n 1 net_admin n 1 audit_write n 1 linux_immutable n 1 sys_ptrace n 1 audit_control n 1 ipc_lock n 1 sys_resource n 1 chown n 1 class cap2_userns 6 mac_override n 1 mac_admin n 1 syslog n 1 block_suspend n 1 wake_alarm n 1 audit_read n 1 setools-4.1.1/setools/permmap.py000066400000000000000000000401411314142262400167070ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys import logging import copy from collections import OrderedDict from errno import ENOENT import pkg_resources from . import exception from . import policyrep from .descriptors import PermissionMapDescriptor from .policyrep import TERuletype infoflow_directions = ["r", "w", "b", "n", "u"] min_weight = 1 max_weight = 10 class PermissionMap(object): """Permission Map for information flow analysis.""" def __init__(self, permmapfile=None): """ Parameter: permmapfile The path to the permission map to load. """ self.log = logging.getLogger(__name__) self.permmap = OrderedDict() self.permmapfile = None if permmapfile: self.load(permmapfile) else: distro = pkg_resources.get_distribution("setools") # pylint: disable=no-member path = "{0}/setools/perm_map".format(distro.location) self.load(path) def __str__(self): return self.permmapfile def __deepcopy__(self, memo): newobj = PermissionMap.__new__(PermissionMap) newobj.log = self.log newobj.permmap = copy.deepcopy(self.permmap) newobj.permmapfile = self.permmapfile memo[id(self)] = newobj return newobj def __iter__(self): for cls in self.classes(): for mapping in self.perms(cls): yield mapping def load(self, permmapfile): """ Parameter: permmapfile The path to the permission map to load. """ self.log.info("Opening permission map \"{0}\"".format(permmapfile)) # state machine # 1 = read number of classes # 2 = read class name and number of perms # 3 = read perms with open(permmapfile, "r") as mapfile: total_perms = 0 class_count = 0 num_classes = 0 state = 1 self.permmap.clear() for line_num, line in enumerate(mapfile, start=1): entry = line.split() if len(entry) == 0 or entry[0][0] == '#': continue if state == 1: try: num_classes = int(entry[0]) except ValueError: raise exception.PermissionMapParseError( "{0}:{1}:Invalid number of classes: {2}". format(permmapfile, line_num, entry[0])) if num_classes < 1: raise exception.PermissionMapParseError( "{0}:{1}:Number of classes must be positive: {2}". format(permmapfile, line_num, entry[0])) state = 2 elif state == 2: if len(entry) != 3 or entry[0] != "class": raise exception.PermissionMapParseError( "{0}:{1}:Invalid class declaration: {2}". format(permmapfile, line_num, entry)) class_name = str(entry[1]) try: num_perms = int(entry[2]) except ValueError: raise exception.PermissionMapParseError( "{0}:{1}:Invalid number of permissions: {2}". format(permmapfile, line_num, entry[2])) if num_perms < 1: raise exception.PermissionMapParseError( "{0}:{1}:Number of permissions must be positive: {2}". format(permmapfile, line_num, entry[2])) class_count += 1 if class_count > num_classes: raise exception.PermissionMapParseError( "{0}:{1}:Extra class found: {2}". format(permmapfile, line_num, class_name)) self.permmap[class_name] = OrderedDict() perm_count = 0 state = 3 elif state == 3: perm_name = str(entry[0]) flow_direction = str(entry[1]) if flow_direction not in infoflow_directions: raise exception.PermissionMapParseError( "{0}:{1}:Invalid information flow direction: {2}". format(permmapfile, line_num, entry[1])) try: weight = int(entry[2]) except ValueError: raise exception.PermissionMapParseError( "{0}:{1}:Invalid permission weight: {2}". format(permmapfile, line_num, entry[2])) if not min_weight <= weight <= max_weight: raise exception.PermissionMapParseError( "{0}:{1}:Permission weight must be {3}-{4}: {2}". format(permmapfile, line_num, entry[2], min_weight, max_weight)) self.log.debug("Read {0}:{1} {2} {3}".format( class_name, perm_name, flow_direction, weight)) if flow_direction == 'u': self.log.info("Permission {0}:{1} is unmapped.".format( class_name, perm_name)) mapping = Mapping(self.permmap, class_name, perm_name, create=True) mapping.direction = flow_direction mapping.weight = weight total_perms += 1 perm_count += 1 if perm_count >= num_perms: state = 2 self.permmapfile = permmapfile self.log.info("Successfully opened permission map \"{0}\"".format(permmapfile)) self.log.debug("Read {0} classes and {1} total permissions.".format( class_count, total_perms)) def save(self, permmapfile): """ Save the permission map to the specified path. Existing files will be overwritten. Parameter: permmapfile The path to write the permission map. """ with open(permmapfile, "w") as mapfile: self.log.info("Writing permission map to \"{0}\"".format(permmapfile)) mapfile.write("{0}\n\n".format(len(self.permmap))) for classname, perms in self.permmap.items(): mapfile.write("class {0} {1}\n".format(classname, len(perms))) for permname, settings in perms.items(): direction = settings['direction'] weight = settings['weight'] assert min_weight <= weight <= max_weight, \ "{0}:{1} weight is out of range ({2}). This is an SETools bug.".format( classname, permname, weight) assert direction in infoflow_directions, \ "{0}:{1} flow direction ({2}) is invalid. This is an SETools bug.".format( classname, permname, direction) if direction == 'u': self.log.warning("Warning: permission {0} in class {1} is unmapped.".format( permname, classname)) mapfile.write("{0:>20} {1:>9} {2:>9}\n".format(permname, direction, weight)) mapfile.write("\n") self.log.info("Successfully wrote permission map to \"{0}\"".format(permmapfile)) def classes(self): """ Generate class names in the permission map. Yield: class An object class name. """ for cls in self.permmap.keys(): yield cls def perms(self, class_): """ Generate permission mappings for the specified class. Parameter: class_ An object class name. Yield: Mapping A permission's complete map (weight, direction, enabled) """ try: for perm in self.permmap[class_].keys(): yield Mapping(self.permmap, class_, perm) except KeyError: raise exception.UnmappedClass("{0} is not mapped.".format(class_)) def mapping(self, class_, perm): """Retrieve a specific permission's mapping.""" return Mapping(self.permmap, class_, perm) def exclude_class(self, class_): """ Exclude all permissions in an object class for calculating rule weights. Parameter: class_ The object class to exclude. Exceptions: UnmappedClass The specified object class is not mapped. """ for perm in self.perms(class_): perm.enabled = False def exclude_permission(self, class_, permission): """ Exclude a permission for calculating rule weights. Parameter: class_ The object class of the permission. permission The permission name to exclude. Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self.permmap, class_, permission).enabled = False def include_class(self, class_): """ Include all permissions in an object class for calculating rule weights. Parameter: class_ The object class to include. Exceptions: UnmappedClass The specified object class is not mapped. """ for perm in self.perms(class_): perm.enabled = True def include_permission(self, class_, permission): """ Include a permission for calculating rule weights. Parameter: class_ The object class of the permission. permission The permission name to include. Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self.permmap, class_, permission).enabled = True def map_policy(self, policy): """Create mappings for all classes and permissions in the specified policy.""" for class_ in policy.classes(): class_name = str(class_) if class_name not in self.permmap: self.log.debug("Adding unmapped class {0} from {1}".format(class_name, policy)) self.permmap[class_name] = OrderedDict() perms = class_.perms try: perms |= class_.common.perms except policyrep.exception.NoCommon: pass for perm_name in perms: if perm_name not in self.permmap[class_name]: self.log.debug("Adding unmapped permission {0} in {1} from {2}". format(perm_name, class_name, policy)) Mapping(self.permmap, class_name, perm_name, create=True) def rule_weight(self, rule): """ Get the type enforcement rule's information flow read and write weights. Parameter: rule A type enforcement rule. Return: Tuple(read_weight, write_weight) read_weight The type enforcement rule's read weight. write_weight The type enforcement rule's write weight. """ write_weight = 0 read_weight = 0 class_name = str(rule.tclass) if rule.ruletype != TERuletype.allow: raise exception.RuleTypeError("{0} rules cannot be used for calculating a weight". format(rule.ruletype)) # iterate over the permissions and determine the # weight of the rule in each direction. The result # is the largest-weight permission in each direction for perm_name in rule.perms: mapping = Mapping(self.permmap, class_name, perm_name) if not mapping.enabled: continue if mapping.direction == "r": read_weight = max(read_weight, mapping.weight) elif mapping.direction == "w": write_weight = max(write_weight, mapping.weight) elif mapping.direction == "b": read_weight = max(read_weight, mapping.weight) write_weight = max(write_weight, mapping.weight) return (read_weight, write_weight) def set_direction(self, class_, permission, direction): """ Set the information flow direction of a permission. Parameter: class_ The object class of the permission. permission The permission name. direction The information flow direction the permission (r/w/b/n). Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self.permmap, class_, permission).direction = direction def set_weight(self, class_, permission, weight): """ Set the weight of a permission. Parameter: class_ The object class of the permission. permission The permission name. weight The weight of the permission (1-10). Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self.permmap, class_, permission).weight = weight # # Settings Validation Functions # def validate_weight(weight): if not min_weight <= weight <= max_weight: raise ValueError("Permission weights must be 1-10: {0}".format(weight)) return weight def validate_direction(direction): if direction not in infoflow_directions: raise ValueError("Invalid information flow direction: {0}".format(direction)) return direction def validate_enabled(enabled): return bool(enabled) class Mapping(object): """A mapping for a permission in the permission map.""" weight = PermissionMapDescriptor("weight", validate_weight) direction = PermissionMapDescriptor("direction", validate_direction) enabled = PermissionMapDescriptor("enabled", validate_enabled) def __init__(self, perm_map, classname, permission, create=False): self.perm_map = perm_map self.class_ = classname self.perm = permission if create: if classname not in self.perm_map: self.perm_map[classname] = OrderedDict() self.perm_map[classname][permission] = {'direction': 'u', 'weight': 1, 'enabled': True} else: if classname not in self.perm_map: raise exception.UnmappedClass("{0} is not mapped.".format(classname)) if permission not in self.perm_map[classname]: raise exception.UnmappedPermission("{0}:{1} is not mapped.". format(classname, permission)) def __lt__(self, other): if self.class_ == other.class_: return self.perm < other.perm else: return self.class_ < other.class_ setools-4.1.1/setools/pirqconquery.py000066400000000000000000000057161314142262400200200ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchContext from .query import PolicyQuery class PirqconQuery(MatchContext, PolicyQuery): """ Pirqcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: irq A single IRQ value. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _irq = None @property def irq(self): return self._irq @irq.setter def irq(self, value): if value: if value < 1: raise ValueError("The IRQ must be positive: {0}".format(value)) self._irq = value else: self._irq = None def __init__(self, policy, **kwargs): super(PirqconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching pirqcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("IRQ: {0.irq!r}".format(self)) self._match_context_debug(self.log) for pirqcon in self.policy.pirqcons(): if self.irq and self.irq != pirqcon.irq: continue if not self._match_context(pirqcon.context): continue yield pirqcon setools-4.1.1/setools/polcapquery.py000066400000000000000000000032131314142262400176110ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .mixins import MatchName from .query import PolicyQuery class PolCapQuery(MatchName, PolicyQuery): """ Query SELinux policy capabilities Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the policy capability to match. name_regex If true, regular expression matching will be used for matching the name. """ def __init__(self, policy, **kwargs): super(PolCapQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching policy capabilities.""" self.log.info("Generating policy capability results from {0.policy}".format(self)) self._match_name_debug(self.log) for cap in self.policy.polcaps(): if not self._match_name(cap): continue yield cap setools-4.1.1/setools/policyrep/000077500000000000000000000000001314142262400167025ustar00rootroot00000000000000setools-4.1.1/setools/policyrep/__init__.py000066400000000000000000000027561314142262400210250ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # Create a Python representation of the policy. # The idea is that this is module provides convenient # abstractions and methods for accessing the policy # structures. from . import exception from .bounds import BoundsRuletype from .netcontext import PortconProtocol, PortconRange from .constraint import ConstraintRuletype from .default import DefaultRuletype, DefaultValue, DefaultRangeValue from .fscontext import FSUseRuletype from .mlsrule import MLSRuletype from .netcontext import NodeconIPVersion, PortconProtocol, PortconRange from .rbacrule import RBACRuletype from .selinuxpolicy import SELinuxPolicy, HandleUnknown, PolicyTarget from .terule import IoctlSet, TERuletype from .xencontext import IomemconRange, IoportconRange setools-4.1.1/setools/policyrep/boolcond.py000066400000000000000000000205011314142262400210510ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from itertools import product from collections import namedtuple from . import exception from . import qpol from . import symbol truth_table_row = namedtuple("truth_table_row", ["values", "result"]) def boolean_factory(policy, name): """Factory function for creating Boolean statement objects.""" if isinstance(name, Boolean): assert name.policy == policy return name elif isinstance(name, qpol.qpol_bool_t): return Boolean(policy, name) try: return Boolean(policy, qpol.qpol_bool_t(policy, str(name))) except ValueError: raise exception.InvalidBoolean("{0} is not a valid Boolean".format(name)) def condexpr_factory(policy, name): """Factory function for creating conditional expression objects.""" if not isinstance(name, qpol.qpol_cond_t): raise TypeError("Conditional expressions cannot be looked up.") return ConditionalExpr(policy, name) class Boolean(symbol.PolicySymbol): """A Boolean.""" @property def state(self): """The default state of the Boolean.""" return bool(self.qpol_symbol.state(self.policy)) def statement(self): """The policy statement.""" return "bool {0} {1};".format(self, str(self.state).lower()) class ConditionalExpr(symbol.PolicySymbol): """A conditional policy expression.""" _cond_expr_val_to_text = { qpol.QPOL_COND_EXPR_NOT: "!", qpol.QPOL_COND_EXPR_OR: "||", qpol.QPOL_COND_EXPR_AND: "&&", qpol.QPOL_COND_EXPR_XOR: "^", qpol.QPOL_COND_EXPR_EQ: "==", qpol.QPOL_COND_EXPR_NEQ: "!="} _cond_expr_val_to_precedence = { qpol.QPOL_COND_EXPR_NOT: 5, qpol.QPOL_COND_EXPR_OR: 1, qpol.QPOL_COND_EXPR_AND: 3, qpol.QPOL_COND_EXPR_XOR: 2, qpol.QPOL_COND_EXPR_EQ: 4, qpol.QPOL_COND_EXPR_NEQ: 4} def __contains__(self, other): for expr_node in self.qpol_symbol.expr_node_iter(self.policy): expr_node_type = expr_node.expr_type(self.policy) if expr_node_type == qpol.QPOL_COND_EXPR_BOOL and other == \ boolean_factory(self.policy, expr_node.get_boolean(self.policy)): return True return False def __str__(self): # qpol representation is in postfix notation. This code # converts it to infix notation. Parentheses are added # to ensure correct expressions, though they may end up # being overused. Set previous operator at start to the # highest precedence (NOT) so if there is a single binary # operator, no parentheses are output stack = [] prev_op_precedence = self._cond_expr_val_to_precedence[qpol.QPOL_COND_EXPR_NOT] for expr_node in self.qpol_symbol.expr_node_iter(self.policy): expr_node_type = expr_node.expr_type(self.policy) if expr_node_type == qpol.QPOL_COND_EXPR_BOOL: # append the boolean name nodebool = boolean_factory( self.policy, expr_node.get_boolean(self.policy)) stack.append(str(nodebool)) elif expr_node_type == qpol.QPOL_COND_EXPR_NOT: # unary operator operand = stack.pop() operator = self._cond_expr_val_to_text[expr_node_type] op_precedence = self._cond_expr_val_to_precedence[expr_node_type] # NOT is the highest precedence, so only need # parentheses if the operand is a subexpression if isinstance(operand, list): subexpr = [operator, "(", operand, ")"] else: subexpr = [operator, operand] stack.append(subexpr) prev_op_precedence = op_precedence else: operand1 = stack.pop() operand2 = stack.pop() operator = self._cond_expr_val_to_text[expr_node_type] op_precedence = self._cond_expr_val_to_precedence[expr_node_type] if prev_op_precedence > op_precedence: # if previous operator is of higher precedence # no parentheses are needed. subexpr = [operand1, operator, operand2] else: subexpr = ["(", operand1, operator, operand2, ")"] stack.append(subexpr) prev_op_precedence = op_precedence return self.__unwind_subexpression(stack) def __unwind_subexpression(self, expr): ret = [] # do a string.join on sublists (subexpressions) for i in expr: if isinstance(i, list): ret.append(self.__unwind_subexpression(i)) else: ret.append(i) return ' '.join(ret) @property def booleans(self): """The set of Booleans in the expression.""" bools = set() for expr_node in self.qpol_symbol.expr_node_iter(self.policy): expr_node_type = expr_node.expr_type(self.policy) if expr_node_type == qpol.QPOL_COND_EXPR_BOOL: bools.add(boolean_factory(self.policy, expr_node.get_boolean(self.policy))) return bools def evaluate(self, **kwargs): """ Evaluate the expression with the stated boolean values. Keyword Parameters: Each keyword parameter name corresponds to a boolean name in the expression Return: bool """ bools = sorted(self.booleans) if sorted(kwargs.keys()) != bools: raise ValueError("Boolean values not set correctly.") stack = [] for expr_node in self.qpol_symbol.expr_node_iter(self.policy): expr_node_type = expr_node.expr_type(self.policy) if expr_node_type == qpol.QPOL_COND_EXPR_BOOL: nodebool = boolean_factory(self.policy, expr_node.get_boolean(self.policy)) stack.append(kwargs[nodebool]) elif expr_node_type == qpol.QPOL_COND_EXPR_NOT: operand = stack.pop() operator = self._cond_expr_val_to_text[expr_node_type] stack.append(not operand) else: operand1 = stack.pop() operand2 = stack.pop() operator = self._cond_expr_val_to_text[expr_node_type] if operator == "||": stack.append(operand1 or operand2) elif operator == "&&": stack.append(operand1 and operand2) elif operator == "^": stack.append(operand1 ^ operand2) elif operator == "==": stack.append(operand1 == operand2) else: # not equal stack.append(operand1 != operand2) return stack[0] def truth_table(self): """ Generate a truth table for this expression. Return: list List item: tuple: values, result Tuple item: values: Dictionary keyed on Boolean names with each value being T/F. result: Evaluation result for the expression given the values. """ bools = sorted(str(b) for b in self.booleans) truth_table = [] # create a list of all combinations of T/F for each Boolean truth_list = list(product([True, False], repeat=len(bools))) for row in truth_list: values = {bools[i]: row[i] for i in range(len(bools))} truth_table.append(truth_table_row(values, self.evaluate(**values))) return truth_table def statement(self): raise exception.NoStatement setools-4.1.1/setools/policyrep/bounds.py000066400000000000000000000037601314142262400205540ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from .symbol import PolicySymbol from .qpol import qpol_typebounds_t from .typeattr import type_factory from .util import PolicyEnum def bounds_factory(policy, sym): """Factory for creating bounds statement objects.""" if isinstance(sym, qpol_typebounds_t): return Bounds(policy, sym) else: raise TypeError("typebounds rules cannot be looked up.") def validate_ruletype(t): """Validate *bounds rule types.""" try: return BoundsRuletype.lookup(t) except KeyError: raise exception.InvalidBoundsType("{0} is not a valid *bounds rule type.".format(t)) class BoundsRuletype(PolicyEnum): """Enumeration of *bounds rule types.""" typebounds = 1 class Bounds(PolicySymbol): """A typebounds statement.""" def __str__(self): return "{0.ruletype} {0.parent} {0.child};".format(self) def __hash__(self): return hash("{0.ruletype}|{0.child};".format(self)) ruletype = BoundsRuletype.typebounds @property def parent(self): return type_factory(self.policy, self.qpol_symbol.parent_name(self.policy)) @property def child(self): return type_factory(self.policy, self.qpol_symbol.child_name(self.policy)) setools-4.1.1/setools/policyrep/constraint.py000066400000000000000000000304331314142262400214430ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import qpol from .exception import ConstraintUseError, InvalidConstraintType from .role import role_factory from .symbol import PolicySymbol from .objclass import class_factory from .typeattr import type_or_attr_factory from .user import user_factory from .util import PolicyEnum def _is_mls(policy, sym): """Determine if this is a regular or MLS constraint/validatetrans.""" # this can only be determined by inspecting the expression. for expr_node in sym.expr_iter(policy): sym_type = expr_node.sym_type(policy) expr_type = expr_node.expr_type(policy) if expr_type == qpol.QPOL_CEXPR_TYPE_ATTR and sym_type >= qpol.QPOL_CEXPR_SYM_L1L2: return True return False def validate_ruletype(t): """Validate constraint rule types.""" try: return ConstraintRuletype.lookup(t) except KeyError: raise InvalidConstraintType("{0} is not a valid constraint type.".format(t)) def constraint_factory(policy, sym): """Factory function for creating constraint objects.""" try: if _is_mls(policy, sym): if isinstance(sym, qpol.qpol_constraint_t): return Constraint(policy, sym, ConstraintRuletype.mlsconstrain) else: return Validatetrans(policy, sym, ConstraintRuletype.mlsvalidatetrans) else: if isinstance(sym, qpol.qpol_constraint_t): return Constraint(policy, sym, ConstraintRuletype.constrain) else: return Validatetrans(policy, sym, ConstraintRuletype.validatetrans) except AttributeError: raise TypeError("Constraints cannot be looked-up.") class ConstraintRuletype(PolicyEnum): """Enumeration of constraint types.""" constrain = 1 mlsconstrain = 2 validatetrans = 3 mlsvalidatetrans = 4 class BaseConstraint(PolicySymbol): """Base class for constraint rules.""" _role_syms = [qpol.QPOL_CEXPR_SYM_ROLE, qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_TARGET, qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_XTARGET] _type_syms = [qpol.QPOL_CEXPR_SYM_TYPE, qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_TARGET, qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_XTARGET] _user_syms = [qpol.QPOL_CEXPR_SYM_USER, qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_TARGET, qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_XTARGET] def __init__(self, policy, qpol_symbol, ruletype): PolicySymbol.__init__(self, policy, qpol_symbol) self.ruletype = ruletype def __str__(self): raise NotImplementedError # There is no levels function as specific # levels cannot be used in expressions, only # the l1, h1, etc. symbols @property def roles(self): """The roles used in the expression.""" return set(self._get_symbols(self._role_syms, role_factory)) @property def perms(self): raise NotImplementedError def statement(self): return str(self) @property def tclass(self): """Object class for this constraint.""" return class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) @property def types(self): """The types and type attributes used in the expression.""" return set(self._get_symbols(self._type_syms, type_or_attr_factory)) @property def users(self): """The users used in the expression.""" return set(self._get_symbols(self._user_syms, user_factory)) def expression(self): """ The constraint's expression in infix notation. Return: list """ _precedence = { "not": 4, "and": 2, "or": 1, "==": 3, "!=": 3, "dom": 3, "domby": 3, "incomp": 3} _max_precedence = 4 _operands = ["u1", "u2", "u3", "r1", "r2", "r3", "t1", "t2", "t3", "l1", "l2", "h1", "h2"] # qpol representation is in postfix notation. This code # converts it to infix notation. Parentheses are added # to ensure correct expressions, though they may end up # being overused. Set previous operator at start to the # highest precedence (op) so if there is a single binary # operator, no parentheses are output stack = [] prev_op_precedence = _max_precedence for op in self.postfix_expression(): if isinstance(op, frozenset) or op in _operands: # operands stack.append(op) else: # operators if op == "not": # unary operator operator = op operand = stack.pop() op_precedence = _precedence[op] stack.append([operator, "(", operand, ")"]) else: # binary operators operand2 = stack.pop() operand1 = stack.pop() operator = op # if previous operator is of higher precedence # no parentheses are needed. if _precedence[op] < prev_op_precedence: stack.append([operand1, operator, operand2]) else: stack.append(["(", operand1, operator, operand2, ")"]) prev_op_precedence = _precedence[op] return self._flatten_expression(stack) def postfix_expression(self): """ The constraint's expression in postfix notation. Return: list """ _expr_type_to_text = { qpol.QPOL_CEXPR_TYPE_NOT: "not", qpol.QPOL_CEXPR_TYPE_AND: "and", qpol.QPOL_CEXPR_TYPE_OR: "or"} _expr_op_to_text = { qpol.QPOL_CEXPR_OP_EQ: "==", qpol.QPOL_CEXPR_OP_NEQ: "!=", qpol.QPOL_CEXPR_OP_DOM: "dom", qpol.QPOL_CEXPR_OP_DOMBY: "domby", qpol.QPOL_CEXPR_OP_INCOMP: "incomp"} _sym_to_text = { qpol.QPOL_CEXPR_SYM_USER: "u1", qpol.QPOL_CEXPR_SYM_ROLE: "r1", qpol.QPOL_CEXPR_SYM_TYPE: "t1", qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_TARGET: "u2", qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_TARGET: "r2", qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_TARGET: "t2", qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_XTARGET: "u3", qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_XTARGET: "r3", qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_XTARGET: "t3", qpol.QPOL_CEXPR_SYM_L1L2: "l1", qpol.QPOL_CEXPR_SYM_L1H2: "l1", qpol.QPOL_CEXPR_SYM_H1L2: "h1", qpol.QPOL_CEXPR_SYM_H1H2: "h1", qpol.QPOL_CEXPR_SYM_L1H1: "l1", qpol.QPOL_CEXPR_SYM_L2H2: "l2", qpol.QPOL_CEXPR_SYM_L1L2 + qpol.QPOL_CEXPR_SYM_TARGET: "l2", qpol.QPOL_CEXPR_SYM_L1H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2", qpol.QPOL_CEXPR_SYM_H1L2 + qpol.QPOL_CEXPR_SYM_TARGET: "l2", qpol.QPOL_CEXPR_SYM_H1H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2", qpol.QPOL_CEXPR_SYM_L1H1 + qpol.QPOL_CEXPR_SYM_TARGET: "h1", qpol.QPOL_CEXPR_SYM_L2H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2"} expression = [] for expr_node in self.qpol_symbol.expr_iter(self.policy): op = expr_node.op(self.policy) sym_type = expr_node.sym_type(self.policy) expr_type = expr_node.expr_type(self.policy) if expr_type == qpol.QPOL_CEXPR_TYPE_ATTR: # logical operator with symbols (e.g. u1 == u2) operand1 = _sym_to_text[sym_type] operand2 = _sym_to_text[sym_type + qpol.QPOL_CEXPR_SYM_TARGET] operator = _expr_op_to_text[op] expression.extend([operand1, operand2, operator]) elif expr_type == qpol.QPOL_CEXPR_TYPE_NAMES: # logical operator with type or attribute list (e.g. t1 == { spam_t eggs_t }) operand1 = _sym_to_text[sym_type] operator = _expr_op_to_text[op] names = list(expr_node.names_iter(self.policy)) if sym_type in self._role_syms: operand2 = frozenset(role_factory(self.policy, n) for n in names) elif sym_type in self._type_syms: operand2 = frozenset(type_or_attr_factory(self.policy, n) for n in names) else: operand2 = frozenset(user_factory(self.policy, n) for n in names) expression.extend([operand1, operand2, operator]) else: # individual operators (and/or/not) expression.append(_expr_type_to_text[expr_type]) return expression # # Internal functions # def _flatten_expression(self, expr): """Flatten the expression into a flat list.""" ret = [] for i in expr: if isinstance(i, list): ret.extend(self._flatten_expression(i)) else: ret.append(i) return ret def _get_symbols(self, syms, factory): """ Internal generator for getting users/roles/types in a constraint expression. Symbols will be yielded multiple times if they appear in the expression multiple times. Parameters: syms List of qpol symbol types. factory The factory function related to these symbols. """ for expr_node in self.qpol_symbol.expr_iter(self.policy): sym_type = expr_node.sym_type(self.policy) expr_type = expr_node.expr_type(self.policy) if expr_type == qpol.QPOL_CEXPR_TYPE_NAMES and sym_type in syms: for s in expr_node.names_iter(self.policy): yield factory(self.policy, s) @staticmethod def _expression_str(expr): """Generate the string representation of the expression.""" ret = [] for item in expr: if isinstance(item, frozenset): if len(item) > 1: ret.append("{{ {0} }} ".format(" ".join(str(j) for j in item))) else: ret.append("{0}".format(" ".join(str(j) for j in item))) else: ret.append(item) return " ".join(ret) class Constraint(BaseConstraint): """A constraint rule (constrain/mlsconstrain).""" def __str__(self): rule_string = "{0.ruletype} {0.tclass} ".format(self) perms = self.perms if len(perms) > 1: rule_string += "{{ {0} }} (".format(' '.join(perms)) else: # convert to list since sets cannot be indexed rule_string += "{0} (".format(list(perms)[0]) rule_string += "{0});".format(self._expression_str(self.expression())) return rule_string @property def perms(self): """The constraint's permission set.""" return set(self.qpol_symbol.perm_iter(self.policy)) class Validatetrans(BaseConstraint): """A validatetrans rule (validatetrans/mlsvalidatetrans).""" def __str__(self): return "{0.ruletype} {0.tclass} ({1});".format(self, self._expression_str(self.expression())) @property def perms(self): raise ConstraintUseError("{0} rules do not have permissions.".format(self.ruletype)) setools-4.1.1/setools/policyrep/context.py000066400000000000000000000041311314142262400207370ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import qpol from . import symbol from . import user from . import role from . import typeattr from . import mls def context_factory(policy, name): """Factory function for creating context objects.""" if not isinstance(name, qpol.qpol_context_t): raise TypeError("Contexts cannot be looked-up.") return Context(policy, name) class Context(symbol.PolicySymbol): """A SELinux security context/security attribute.""" def __str__(self): try: return "{0.user}:{0.role}:{0.type_}:{0.range_}".format(self) except exception.MLSDisabled: return "{0.user}:{0.role}:{0.type_}".format(self) @property def user(self): """The user portion of the context.""" return user.user_factory(self.policy, self.qpol_symbol.user(self.policy)) @property def role(self): """The role portion of the context.""" return role.role_factory(self.policy, self.qpol_symbol.role(self.policy)) @property def type_(self): """The type portion of the context.""" return typeattr.type_factory(self.policy, self.qpol_symbol.type_(self.policy)) @property def range_(self): """The MLS range of the context.""" return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) def statement(self): raise exception.NoStatement setools-4.1.1/setools/policyrep/default.py000066400000000000000000000104111314142262400206750ustar00rootroot00000000000000# Copyright 2014, 2016 Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import symbol from . import objclass from . import qpol from .util import PolicyEnum def validate_ruletype(t): """Validate default_* rule types.""" try: return DefaultRuletype.lookup(t) except KeyError: raise exception.InvalidDefaultType("{0} is not a valid default_* rule type.".format(t)) def validate_default_value(default): try: return DefaultValue.lookup(default) except KeyError: raise exception.InvalidDefaultValue("{0} is not a valid default_* value.".format(default)) def validate_default_range(default): try: return DefaultRangeValue.lookup(default) except KeyError: raise exception.InvalidDefaultRange("{0} is not a valid default_* range.".format(default)) class DefaultRuletype(PolicyEnum): """Enumeration of default rule types.""" default_user = 1 default_role = 2 default_type = 3 default_range = 4 class DefaultValue(PolicyEnum): """Enumeration of default values.""" source = 1 target = 2 class DefaultRangeValue(PolicyEnum): """Enumeration of default range values.""" low = 1 high = 2 low_high = 3 def default_factory(policy, sym): """Factory generator for creating default_* statement objects.""" # The low level policy groups default_* settings by object class. # Since each class can have up to four default_* statements, # this factory function is a generator which yields up to # four Default objects. if not isinstance(sym, qpol.qpol_default_object_t): raise NotImplementedError # qpol will essentially iterate over all classes # and emit None for classes that don't set a default. # Because of all of this processing, extract almost # all of the information out of the qpol representation. # (we have to determine almost all of it anyway) if not sym.object_class(policy): raise exception.NoDefaults user = sym.user_default(policy) role = sym.role_default(policy) type_ = sym.type_default(policy) range_ = sym.range_default(policy) if user: obj = Default(policy, sym) obj.ruletype = DefaultRuletype.default_user obj.default = DefaultValue[user] yield obj if role: obj = Default(policy, sym) obj.ruletype = DefaultRuletype.default_role obj.default = DefaultValue[role] yield obj if type_: obj = Default(policy, sym) obj.ruletype = DefaultRuletype.default_type obj.default = DefaultValue[type_] yield obj if range_: # range_ is something like "source low_high" rng = range_.split() obj = RangeDefault(policy, sym) obj.ruletype = DefaultRuletype.default_range obj.default = DefaultValue[rng[0]] obj.default_range = DefaultRangeValue[rng[1]] yield obj class Default(symbol.PolicySymbol): """Base class for default_* statements.""" def __str__(self): return "{0.ruletype} {0.tclass} {0.default};".format(self) def __hash__(self): return hash("{0.ruletype}|{0.tclass}".format(self)) @property def tclass(self): """The object class.""" return objclass.class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) def statement(self): return str(self) class RangeDefault(Default): """A default_range statement.""" default_range = None def __str__(self): return "{0.ruletype} {0.tclass} {0.default} {0.default_range};".format(self) setools-4.1.1/setools/policyrep/exception.py000066400000000000000000000120211314142262400212460ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from ..exception import SEToolsException # # Policyrep base exception # class PolicyrepException(SEToolsException): """Base class for all policyrep exceptions.""" pass # # General Policyrep exceptions # class InvalidPolicy(SyntaxError, PolicyrepException): """Exception for invalid policy.""" pass class MLSDisabled(PolicyrepException): """ Exception when MLS is disabled. """ pass # # Invalid component exceptions # class InvalidSymbol(ValueError, PolicyrepException): """ Base class for invalid symbols. Typically this is attempting to look up an object in the policy, but it does not exist. """ pass class InvalidBoolean(InvalidSymbol): """Exception for invalid Booleans.""" pass class InvalidCategory(InvalidSymbol): """Exception for invalid MLS categories.""" pass class InvalidClass(InvalidSymbol): """Exception for invalid object classes.""" pass class InvalidCommon(InvalidSymbol): """Exception for invalid common permission sets.""" pass class InvalidInitialSid(InvalidSymbol): """Exception for invalid initial sids.""" pass class InvalidLevel(InvalidSymbol): """ Exception for an invalid level. """ pass class InvalidLevelDecl(InvalidSymbol): """ Exception for an invalid level declaration. """ pass class InvalidRange(InvalidSymbol): """ Exception for an invalid range. """ pass class InvalidRole(InvalidSymbol): """Exception for invalid roles.""" pass class InvalidSensitivity(InvalidSymbol): """ Exception for an invalid sensitivity. """ pass class InvalidType(InvalidSymbol): """Exception for invalid types and attributes.""" pass class InvalidUser(InvalidSymbol): """Exception for invalid users.""" pass # # Rule type exceptions # class InvalidRuleType(InvalidSymbol): """Exception for invalid rule types.""" pass class InvalidBoundsType(InvalidSymbol): """Exception for invalid *bounds rule types.""" pass class InvalidConstraintType(InvalidSymbol): """Exception for invalid constraint types.""" pass class InvalidDefaultType(InvalidRuleType): """Exception for invalid default_* types.""" pass class InvalidFSUseType(InvalidRuleType): """Exception for invalid fs_use_* types.""" pass class InvalidMLSRuleType(InvalidRuleType): """Exception for invalid MLS rule types.""" pass class InvalidRBACRuleType(InvalidRuleType): """Exception for invalid RBAC rule types.""" pass class InvalidTERuleType(InvalidRuleType): """Exception for invalid TE rule types.""" pass # # Object use errors # class SymbolUseError(AttributeError, PolicyrepException): """ Base class for incorrectly using an object. Typically this is for classes with strong similarities, but with slight variances in functionality, e.g. allow vs type_transition rules. """ pass class RuleUseError(SymbolUseError): """ Base class for incorrect parameters for a rule. For example, trying to get the permissions of a rule that has no permissions. """ pass class ConstraintUseError(SymbolUseError): """Exception when getting permissions from a validatetrans.""" pass class NoStatement(SymbolUseError): """ Exception for objects that have no inherent statement, such as conditional expressions and MLS ranges. """ pass # # Default rule exceptions # class InvalidDefaultValue(InvalidSymbol): """Exception for invalid default (not source/target)""" pass class InvalidDefaultRange(InvalidSymbol): """Exception for invalid default range""" pass # # Other exceptions # class NoCommon(AttributeError, PolicyrepException): """ Exception when a class does not inherit a common permission set. """ pass class NoDefaults(InvalidSymbol): """Exception for classes that have no default_* statements.""" pass class RuleNotConditional(AttributeError, PolicyrepException): """ Exception when getting the conditional expression for rules that are unconditional (not conditional). """ pass class TERuleNoFilename(AttributeError, PolicyrepException): """ Exception when getting the file name of a type_transition rule that has no file name. """ pass setools-4.1.1/setools/policyrep/fscontext.py000066400000000000000000000106651314142262400213010ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import stat from . import exception from . import qpol from . import symbol from . import context from .util import PolicyEnum def validate_ruletype(t): """Validate fs_use_* rule types.""" try: return FSUseRuletype.lookup(t) except KeyError: raise exception.InvalidFSUseType("{0} is not a valid fs_use_* type.".format(t)) def fs_use_factory(policy, name): """Factory function for creating fs_use_* objects.""" if not isinstance(name, qpol.qpol_fs_use_t): raise TypeError("fs_use_* cannot be looked-up.") return FSUse(policy, name) def genfscon_factory(policy, name): """Factory function for creating genfscon objects.""" if not isinstance(name, qpol.qpol_genfscon_t): raise TypeError("Genfscons cannot be looked-up.") return Genfscon(policy, name) class FSContext(symbol.PolicySymbol): """Base class for in-policy labeling rules.""" def __str__(self): raise NotImplementedError @property def fs(self): """The filesystem type for this statement.""" return self.qpol_symbol.name(self.policy) @property def context(self): """The context for this statement.""" return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) def statement(self): return str(self) class GenfsFiletype(int): """ A genfscon file type. The possible values are equivalent to file type values in the stat module, e.g. S_IFBLK, but overrides the string representation with the corresponding genfscon file type string (-b, -c, etc.) If the genfscon has no specific file type, this is 0, (empty string). """ _filetype_to_text = { 0: "", stat.S_IFBLK: "-b", stat.S_IFCHR: "-c", stat.S_IFDIR: "-d", stat.S_IFIFO: "-p", stat.S_IFREG: "--", stat.S_IFLNK: "-l", stat.S_IFSOCK: "-s"} def __str__(self): return self._filetype_to_text[self] class Genfscon(FSContext): """A genfscon statement.""" def __str__(self): return "genfscon {0.fs} {0.path} {0.filetype} {0.context}".format(self) def __hash__(self): return hash("genfscon|{0.fs}|{0.path}|{0.filetype}".format(self)) def __eq__(self, other): # Libqpol allocates new C objects in the # genfscons iterator, so pointer comparison # in the PolicySymbol object doesn't work. try: return (self.fs == other.fs and self.path == other.path and self.filetype == other.filetype and self.context == other.context) except AttributeError: return str(self) == str(other) @property def filetype(self): """The file type (e.g. stat.S_IFBLK) for this genfscon statement.""" return GenfsFiletype(self.qpol_symbol.object_class(self.policy)) @property def path(self): """The path for this genfscon statement.""" return self.qpol_symbol.path(self.policy) class FSUseRuletype(PolicyEnum): """Enumeration of fs_use_* rule types.""" # there are more rule types, but modern SELinux # only supports these three. fs_use_xattr = qpol.QPOL_FS_USE_XATTR fs_use_trans = qpol.QPOL_FS_USE_TRANS fs_use_task = qpol.QPOL_FS_USE_TASK class FSUse(FSContext): """An fs_use_* statement.""" def __str__(self): return "{0.ruletype} {0.fs} {0.context};".format(self) def __hash__(self): return hash("{0.ruletype}|{0.fs}".format(self)) @property def ruletype(self): """The rule type for this fs_use_* statement.""" return FSUseRuletype(self.qpol_symbol.behavior(self.policy)) setools-4.1.1/setools/policyrep/initsid.py000066400000000000000000000031111314142262400207130ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import qpol from . import symbol from . import context def initialsid_factory(policy, name): """Factory function for creating initial sid objects.""" if isinstance(name, InitialSID): assert name.policy == policy return name elif isinstance(name, qpol.qpol_isid_t): return InitialSID(policy, name) try: return InitialSID(policy, qpol.qpol_isid_t(policy, name)) except ValueError: raise exception.InvalidInitialSid("{0} is not a valid initial sid".format(name)) class InitialSID(symbol.PolicySymbol): """An initial SID statement.""" @property def context(self): """The context for this initial SID.""" return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) def statement(self): return "sid {0} {0.context}".format(self) setools-4.1.1/setools/policyrep/mls.py000066400000000000000000000344231314142262400200550ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=protected-access import itertools from . import exception from . import qpol from . import symbol # qpol does not expose an equivalent of a sensitivity declaration. # qpol_level_t is equivalent to the level declaration: # level s0:c0.c1023; # qpol_mls_level_t represents a level as used in contexts, # such as range_transitions or labeling statements such as # portcon and nodecon. # Here qpol_level_t is also used for MLSSensitivity # since it has the sensitivity name, dominance, and there # is a 1:1 correspondence between the sensitivity declarations # and level declarations. # Hashing has to be handled below because the qpol references, # normally used for a hash key, are not the same for multiple # instances of the same object (except for level decl). def enabled(policy): """Determine if MLS is enabled.""" return bool(policy.capability(qpol.QPOL_CAP_MLS)) def category_factory(policy, sym): """Factory function for creating MLS category objects.""" if not enabled(policy): raise exception.MLSDisabled if isinstance(sym, Category): assert sym.policy == policy return sym elif isinstance(sym, qpol.qpol_cat_t): if sym.isalias(policy): raise TypeError("{0} is an alias".format(sym.name(policy))) return Category(policy, sym) try: return Category(policy, qpol.qpol_cat_t(policy, str(sym))) except ValueError: raise exception.InvalidCategory("{0} is not a valid category".format(sym)) def sensitivity_factory(policy, sym): """Factory function for creating MLS sensitivity objects.""" if not enabled(policy): raise exception.MLSDisabled if isinstance(sym, Sensitivity): assert sym.policy == policy return sym elif isinstance(sym, qpol.qpol_level_t): if sym.isalias(policy): raise TypeError("{0} is an alias".format(sym.name(policy))) return Sensitivity(policy, sym) try: return Sensitivity(policy, qpol.qpol_level_t(policy, str(sym))) except ValueError: raise exception.InvalidSensitivity("{0} is not a valid sensitivity".format(sym)) def level_factory(policy, sym): """ Factory function for creating MLS level objects (e.g. levels used in contexts of labeling statements) """ if not enabled(policy): raise exception.MLSDisabled if isinstance(sym, Level): assert sym.policy == policy return sym elif isinstance(sym, qpol.qpol_mls_level_t): return Level(policy, sym) sens_split = str(sym).split(":") sens = sens_split[0] try: semantic_level = qpol.qpol_semantic_level_t(policy, sens) except ValueError: raise exception.InvalidLevel("{0} is not a valid level ({1} is not a valid sensitivity)". format(sym, sens)) try: cats = sens_split[1] except IndexError: pass else: for group in cats.split(","): catrange = group.split(".") if len(catrange) == 2: try: semantic_level.add_cats(policy, catrange[0], catrange[1]) except ValueError: raise exception.InvalidLevel( "{0} is not a valid level ({1} is not a valid category range)". format(sym, group)) elif len(catrange) == 1: try: semantic_level.add_cats(policy, catrange[0], catrange[0]) except ValueError: raise exception.InvalidLevel( "{0} is not a valid level ({1} is not a valid category)".format(sym, group)) else: raise exception.InvalidLevel( "{0} is not a valid level (level parsing error)".format(sym)) # convert to level object try: policy_level = qpol.qpol_mls_level_t(policy, semantic_level) except ValueError: raise exception.InvalidLevel( "{0} is not a valid level (one or more categories are not associated with the " "sensitivity)".format(sym)) return Level(policy, policy_level) def level_decl_factory(policy, sym): """ Factory function for creating MLS level declaration objects. (level statements) Lookups are only by sensitivity name. """ if not enabled(policy): raise exception.MLSDisabled if isinstance(sym, LevelDecl): assert sym.policy == policy return sym elif isinstance(sym, qpol.qpol_level_t): if sym.isalias(policy): raise TypeError("{0} is an alias".format(sym.name(policy))) return LevelDecl(policy, sym) try: return LevelDecl(policy, qpol.qpol_level_t(policy, str(sym))) except ValueError: raise exception.InvalidLevelDecl("{0} is not a valid sensitivity".format(sym)) def range_factory(policy, sym): """Factory function for creating MLS range objects.""" if not enabled(policy): raise exception.MLSDisabled if isinstance(sym, Range): assert sym.policy == policy return sym elif isinstance(sym, qpol.qpol_mls_range_t): return Range(policy, sym) # build range: levels = str(sym).split("-") # strip() levels to handle ranges with spaces in them, # e.g. s0:c1 - s0:c0.c255 try: low = level_factory(policy, levels[0].strip()) except exception.InvalidLevel as ex: raise exception.InvalidRange("{0} is not a valid range ({1}).".format(sym, ex)) try: high = level_factory(policy, levels[1].strip()) except exception.InvalidLevel as ex: raise exception.InvalidRange("{0} is not a valid range ({1}).".format(sym, ex)) except IndexError: high = low # convert to range object try: policy_range = qpol.qpol_mls_range_t(policy, low.qpol_symbol, high.qpol_symbol) except ValueError: raise exception.InvalidRange("{0} is not a valid range ({1} is not dominated by {2})". format(sym, low, high)) return Range(policy, policy_range) class BaseMLSComponent(symbol.PolicySymbol): """Base class for sensitivities and categories.""" @property def _value(self): """ The value of the component. This is a low-level policy detail exposed for internal use only. """ return self.qpol_symbol.value(self.policy) def aliases(self): """Generator that yields all aliases for this category.""" for alias in self.qpol_symbol.alias_iter(self.policy): yield alias class Category(BaseMLSComponent): """An MLS category.""" def statement(self): aliases = list(self.aliases()) stmt = "category {0}".format(self) if aliases: if len(aliases) > 1: stmt += " alias {{ {0} }}".format(' '.join(aliases)) else: stmt += " alias {0}".format(aliases[0]) stmt += ";" return stmt def __lt__(self, other): """Comparison based on their index instead of their names.""" return self._value < other._value class Sensitivity(BaseMLSComponent): """An MLS sensitivity""" def __ge__(self, other): return self._value >= other._value def __gt__(self, other): return self._value > other._value def __le__(self, other): return self._value <= other._value def __lt__(self, other): return self._value < other._value def statement(self): aliases = list(self.aliases()) stmt = "sensitivity {0}".format(self) if aliases: if len(aliases) > 1: stmt += " alias {{ {0} }}".format(' '.join(aliases)) else: stmt += " alias {0}".format(aliases[0]) stmt += ";" return stmt class BaseMLSLevel(symbol.PolicySymbol): """Base class for MLS levels.""" def __str__(self): lvl = str(self.sensitivity) # sort by policy declaration order cats = sorted(self.categories(), key=lambda k: k._value) if cats: # generate short category notation shortlist = [] for _, i in itertools.groupby(cats, key=lambda k, c=itertools.count(): k._value - next(c)): group = list(i) if len(group) > 1: shortlist.append("{0}.{1}".format(group[0], group[-1])) else: shortlist.append(str(group[0])) lvl += ":" + ','.join(shortlist) return lvl @property def sensitivity(self): raise NotImplementedError def categories(self): """ Generator that yields all individual categories for this level. All categories are yielded, not a compact notation such as c0.c255 """ for cat in self.qpol_symbol.cat_iter(self.policy): yield category_factory(self.policy, cat) class LevelDecl(BaseMLSLevel): """ The declaration statement for MLS levels, e.g: level s7:c0.c1023; """ def __hash__(self): return hash(self.sensitivity) # below comparisons are only based on sensitivity # dominance since, in this context, the allowable # category set is being defined for the level. # object type is asserted here because this cannot # be compared to a Level instance. def __eq__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" try: return self.sensitivity == other.sensitivity except AttributeError: return str(self) == str(other) def __ge__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity >= other.sensitivity def __gt__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity > other.sensitivity def __le__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity <= other.sensitivity def __lt__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity < other.sensitivity @property def sensitivity(self): """The sensitivity of the level.""" # since the qpol symbol for levels is also used for # MLSSensitivity objects, use self's qpol symbol return sensitivity_factory(self.policy, self.qpol_symbol) def statement(self): return "level {0};".format(self) class Level(BaseMLSLevel): """An MLS level used in contexts.""" def __hash__(self): return hash(str(self)) def __eq__(self, other): try: othercats = set(other.categories()) except AttributeError: return str(self) == str(other) else: selfcats = set(self.categories()) return self.sensitivity == other.sensitivity and selfcats == othercats def __ge__(self, other): """Dom operator.""" selfcats = set(self.categories()) othercats = set(other.categories()) return self.sensitivity >= other.sensitivity and selfcats >= othercats def __gt__(self, other): selfcats = set(self.categories()) othercats = set(other.categories()) return ((self.sensitivity > other.sensitivity and selfcats >= othercats) or (self.sensitivity >= other.sensitivity and selfcats > othercats)) def __le__(self, other): """Domby operator.""" selfcats = set(self.categories()) othercats = set(other.categories()) return self.sensitivity <= other.sensitivity and selfcats <= othercats def __lt__(self, other): selfcats = set(self.categories()) othercats = set(other.categories()) return ((self.sensitivity < other.sensitivity and selfcats <= othercats) or (self.sensitivity <= other.sensitivity and selfcats < othercats)) def __xor__(self, other): """Incomp operator.""" return not (self >= other or self <= other) @property def sensitivity(self): """The sensitivity of the level.""" return sensitivity_factory(self.policy, self.qpol_symbol.sens_name(self.policy)) def statement(self): raise exception.NoStatement class Range(symbol.PolicySymbol): """An MLS range""" def __str__(self): high = self.high low = self.low if high == low: return str(low) return "{0} - {1}".format(low, high) def __hash__(self): return hash(str(self)) def __eq__(self, other): try: return self.low == other.low and self.high == other.high except AttributeError: # remove all spaces in the string representations # to handle cases where the other object does not # have spaces around the '-' other_str = str(other).replace(" ", "") self_str = str(self).replace(" ", "") return self_str == other_str def __contains__(self, other): return self.low <= other <= self.high @property def high(self): """The high end/clearance level of this range.""" return level_factory(self.policy, self.qpol_symbol.high_level(self.policy)) @property def low(self): """The low end/current level of this range.""" return level_factory(self.policy, self.qpol_symbol.low_level(self.policy)) def statement(self): raise exception.NoStatement setools-4.1.1/setools/policyrep/mlsrule.py000066400000000000000000000063321314142262400207430ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import itertools from . import exception from . import qpol from . import rule from . import typeattr from . import mls from .util import PolicyEnum def mls_rule_factory(policy, symbol): """Factory function for creating MLS rule objects.""" if not isinstance(symbol, qpol.qpol_range_trans_t): raise TypeError("MLS rules cannot be looked-up.") return MLSRule(policy, symbol) def expanded_mls_rule_factory(original, source, target): """ Factory function for creating expanded MLS rules. original The MLS rule the expanded rule originates from. source The source type of the expanded rule. target The target type of the expanded rule. """ if isinstance(original, ExpandedMLSRule): return original elif isinstance(original, MLSRule): rule = ExpandedMLSRule(original.policy, original.qpol_symbol) else: raise TypeError("The original rule must be a MLS rule class.") rule.source = source rule.target = target rule.origin = original return rule def validate_ruletype(t): """Validate MLS rule types.""" try: return MLSRuletype.lookup(t) except KeyError: raise exception.InvalidMLSRuleType("{0} is not a valid MLS rule type.".format(t)) class MLSRuletype(PolicyEnum): """An enumeration of MLS rule types.""" range_transition = 1 class MLSRule(rule.PolicyRule): """An MLS rule.""" __slots__ = () def __str__(self): return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default};".format(self) ruletype = MLSRuletype.range_transition @property def source(self): """The rule's source type/attribute.""" return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.source_type(self.policy)) @property def target(self): """The rule's target type/attribute.""" return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) @property def default(self): """The rule's default range.""" return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" for s, t in itertools.product(self.source.expand(), self.target.expand()): yield expanded_mls_rule_factory(self, s, t) class ExpandedMLSRule(MLSRule): """An expanded MLS rule.""" __slots__ = ("source", "target", "origin") setools-4.1.1/setools/policyrep/netcontext.py000066400000000000000000000123671314142262400214600ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from socket import AF_INET, AF_INET6, IPPROTO_TCP, IPPROTO_UDP, getprotobyname from collections import namedtuple import socket from . import qpol from . import symbol from . import context from .util import PolicyEnum PortconRange = namedtuple("PortconRange", ["low", "high"]) # Python does not have a constant # for the DCCP protocol. try: IPPROTO_DCCP = getprotobyname("dccp") except socket.error: IPPROTO_DCCP = 33 def netifcon_factory(policy, name): """Factory function for creating netifcon objects.""" if not isinstance(name, qpol.qpol_netifcon_t): raise NotImplementedError return Netifcon(policy, name) def nodecon_factory(policy, name): """Factory function for creating nodecon objects.""" if not isinstance(name, qpol.qpol_nodecon_t): raise NotImplementedError return Nodecon(policy, name) def portcon_factory(policy, name): """Factory function for creating portcon objects.""" if not isinstance(name, qpol.qpol_portcon_t): raise NotImplementedError return Portcon(policy, name) class NetContext(symbol.PolicySymbol): """Base class for in-policy network labeling rules.""" def __str__(self): raise NotImplementedError @property def context(self): """The context for this statement.""" return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) def statement(self): return str(self) class Netifcon(NetContext): """A netifcon statement.""" def __str__(self): return "netifcon {0.netif} {0.context} {0.packet}".format(self) def __hash__(self): return hash("netifcon|{0.netif}".format(self)) @property def netif(self): """The network interface name.""" return self.qpol_symbol.name(self.policy) @property def context(self): """The context for the interface.""" return context.context_factory(self.policy, self.qpol_symbol.if_con(self.policy)) @property def packet(self): """The context for the packets.""" return context.context_factory(self.policy, self.qpol_symbol.msg_con(self.policy)) class NodeconIPVersion(int, PolicyEnum): """Nodecon IP Version""" ipv4 = AF_INET ipv6 = AF_INET6 class Nodecon(NetContext): """A nodecon statement.""" def __str__(self): return "nodecon {0.address} {0.netmask} {0.context}".format(self) def __hash__(self): return hash("nodecon|{0.address}|{0.netmask}".format(self)) def __eq__(self, other): # Libqpol allocates new C objects in the # nodecons iterator, so pointer comparison # in the PolicySymbol object doesn't work. try: return (self.address == other.address and self.netmask == other.netmask and self.context == other.context) except AttributeError: return (str(self) == str(other)) @property def ip_version(self): """ The IP version for the nodecon (socket.AF_INET or socket.AF_INET6). """ return NodeconIPVersion(self.qpol_symbol.protocol(self.policy)) @property def address(self): """The network address for the nodecon.""" return self.qpol_symbol.addr(self.policy) @property def netmask(self): """The network mask for the nodecon.""" return self.qpol_symbol.mask(self.policy) class PortconProtocol(int, PolicyEnum): """A portcon protocol type.""" tcp = IPPROTO_TCP udp = IPPROTO_UDP dccp = IPPROTO_DCCP class Portcon(NetContext): """A portcon statement.""" def __str__(self): low, high = self.ports if low == high: return "portcon {0.protocol} {1} {0.context}".format(self, low) else: return "portcon {0.protocol} {1}-{2} {0.context}".format(self, low, high) def __hash__(self): return hash("portcon|{0.protocol}|{1.low}|{1.high}".format(self, self.ports)) @property def protocol(self): """ The protocol type for the portcon. """ return PortconProtocol(self.qpol_symbol.protocol(self.policy)) @property def ports(self): """ The port range for this portcon. Return: Tuple(low, high) low The low port of the range. high The high port of the range. """ low = self.qpol_symbol.low_port(self.policy) high = self.qpol_symbol.high_port(self.policy) return PortconRange(low, high) setools-4.1.1/setools/policyrep/objclass.py000066400000000000000000000061571314142262400210650ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import symbol from . import qpol def common_factory(policy, name): """Factory function for creating common permission set objects.""" if isinstance(name, Common): assert name.policy == policy return name elif isinstance(name, qpol.qpol_common_t): return Common(policy, name) try: return Common(policy, qpol.qpol_common_t(policy, str(name))) except ValueError: raise exception.InvalidCommon("{0} is not a valid common".format(name)) def class_factory(policy, name): """Factory function for creating object class objects.""" if isinstance(name, ObjClass): assert name.policy == policy return name elif isinstance(name, qpol.qpol_class_t): return ObjClass(policy, name) try: return ObjClass(policy, qpol.qpol_class_t(policy, str(name))) except ValueError: raise exception.InvalidClass("{0} is not a valid object class".format(name)) class Common(symbol.PolicySymbol): """A common permission set.""" def __contains__(self, other): return other in self.perms @property def perms(self): """The list of the common's permissions.""" return set(self.qpol_symbol.perm_iter(self.policy)) def statement(self): return "common {0}\n{{\n\t{1}\n}}".format(self, '\n\t'.join(self.perms)) class ObjClass(Common): """An object class.""" def __contains__(self, other): try: if other in self.common.perms: return True except exception.NoCommon: pass return other in self.perms @property def common(self): """ The common that the object class inherits. Exceptions: NoCommon The object class does not inherit a common. """ try: return common_factory(self.policy, self.qpol_symbol.common(self.policy)) except ValueError: raise exception.NoCommon("{0} does not inherit a common.".format(self)) def statement(self): stmt = "class {0}\n".format(self) try: stmt += "inherits {0}\n".format(self.common) except exception.NoCommon: pass # a class that inherits may not have additional permissions perms = self.perms if len(perms) > 0: stmt += "{{\n\t{0}\n}}".format('\n\t'.join(perms)) return stmt setools-4.1.1/setools/policyrep/polcap.py000066400000000000000000000024151314142262400205340ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import qpol from . import symbol def polcap_factory(policy, name): """Factory function for creating policy capability objects.""" if isinstance(name, PolicyCapability): assert name.policy == policy return name elif isinstance(name, qpol.qpol_polcap_t): return PolicyCapability(policy, name) else: raise TypeError("Policy capabilities cannot be looked up.") class PolicyCapability(symbol.PolicySymbol): """A policy capability.""" def statement(self): return "policycap {0};".format(self) setools-4.1.1/setools/policyrep/qpol.i000066400000000000000000003064351314142262400200420ustar00rootroot00000000000000/** * SWIG declarations for libqpol. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2008 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ %module qpol %{ #include #include #include #include #include "include/qpol/avrule_query.h" #include "include/qpol/bool_query.h" #include "include/qpol/class_perm_query.h" #include "include/qpol/cond_query.h" #include "include/qpol/constraint_query.h" #include "include/qpol/context_query.h" #include "include/qpol/fs_use_query.h" #include "include/qpol/genfscon_query.h" #include "include/qpol/isid_query.h" #include "include/qpol/iterator.h" #include "include/qpol/mls_query.h" #include "include/qpol/mlsrule_query.h" #include "include/qpol/module.h" #include "include/qpol/netifcon_query.h" #include "include/qpol/nodecon_query.h" #include "include/qpol/policy.h" #include "include/qpol/policy_extend.h" #include "include/qpol/portcon_query.h" #include "include/qpol/rbacrule_query.h" #include "include/qpol/role_query.h" #include "include/qpol/terule_query.h" #include "include/qpol/type_query.h" #include "include/qpol/user_query.h" #include "include/qpol/xen_query.h" /* Provide hooks so that language-specific modules can define the * callback function, used by the handler in * qpol_policy_open_from_file(). */ SWIGEXPORT qpol_callback_fn_t qpol_swig_message_callback = NULL; SWIGEXPORT void * qpol_swig_message_callback_arg = NULL; %} %include exception.i %include stdint.i /* handle size_t as architecture dependent */ #ifdef SWIGWORDSIZE64 typedef uint64_t size_t; #else typedef uint32_t size_t; #endif %inline %{ /* cast void * to char * as it can't have a constructor */ const char * to_str(void *x) { return (const char *)x; } /* cast a void * to int, while freeing the pointer */ int to_int_with_free(void *x) { int i = *(int *)x; free(x); return i; } %} %{ /* C Bridge to Python logging callback */ __attribute__ ((format(printf, 4, 0))) static void qpol_log_callback(void *varg, const qpol_policy_t * p __attribute__ ((unused)), int level, const char *fmt, va_list va_args) { /* Expand to a full string to avoid any C format string * or variable args handling when passing to Python */ PyObject *py_callback, *rc; char *str = NULL; if(vasprintf(&str, fmt, va_args) < 0) return; py_callback = (PyObject *) varg; /* this char* casting doesn't make sense, but this runs afoul of -Werror * otherwise as the Python library doesn't do const char* */ rc = PyObject_CallFunction(py_callback, (char*)"(is)", level, str); Py_XDECREF(rc); free(str); } %} %pythoncode %{ import logging from functools import wraps def QpolGenerator(cast): """ A decorator which converts qpol iterators into Python generators. Qpol iterators use void* to be generic about their contents. The purpose of the _from_void functions below is to wrap the pointer casting, hence the "cast" variable name here. Decorator parameter: cast A wrapper function which casts the qpol iterator return pointer to the proper C data type pointer. The Python function reference to the C Python extension is used, for example: @QpolGenerator(_qpol.qpol_type_from_void) """ def decorate(func): @wraps(func) def wrapper(*args, **kwargs): qpol_iter = func(*args) while not qpol_iter.isend(): yield cast(qpol_iter.item()) qpol_iter.next_() return wrapper return decorate def qpol_logger(level, msg): """Log qpol messages via Python logging.""" logging.getLogger(__name__).debug(msg) def qpol_policy_factory(path): """Factory function for qpol policy objects.""" # The main purpose here is to hook in the # above logger callback. return qpol_policy_t(path, 0, qpol_logger) %} /* qpol_policy */ #define QPOL_POLICY_OPTION_NO_NEVERALLOWS 0x00000001 #define QPOL_POLICY_OPTION_NO_RULES 0x00000002 /* add maximum and minimum policy versions supported by the statically linked libsepol */ %constant int QPOL_POLICY_MAX_VERSION = POLICYDB_VERSION_MAX; %constant int QPOL_POLICY_MIN_VERSION = POLICYDB_VERSION_MIN; typedef struct qpol_policy {} qpol_policy_t; typedef void (*qpol_callback_fn_t) (void *varg, struct qpol_policy * policy, int level, const char *fmt, va_list va_args); typedef enum qpol_capability { QPOL_CAP_ATTRIB_NAMES, QPOL_CAP_SYN_RULES, QPOL_CAP_LINE_NUMBERS, QPOL_CAP_CONDITIONALS, QPOL_CAP_MLS, QPOL_CAP_MODULES, QPOL_CAP_RULES_LOADED, QPOL_CAP_SOURCE, QPOL_CAP_NEVERALLOW, QPOL_CAP_POLCAPS, QPOL_CAP_BOUNDS, QPOL_CAP_DEFAULT_OBJECTS, QPOL_CAP_DEFAULT_TYPE, QPOL_CAP_PERMISSIVE, QPOL_CAP_FILENAME_TRANS, QPOL_CAP_ROLETRANS, QPOL_CAP_XPERM_IOCTL } qpol_capability_e; %exception qpol_policy { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_SyntaxError, "Invalid policy."); } else { PyErr_SetFromErrnoWithFilename(PyExc_OSError, arg1); } return NULL; } } %constant int QPOL_TARGET_SELINUX = SEPOL_TARGET_SELINUX; %constant int QPOL_TARGET_XEN = SEPOL_TARGET_XEN; %constant int QPOL_DENY_UNKNOWN = SEPOL_DENY_UNKNOWN; %constant int QPOL_REJECT_UNKNOWN = SEPOL_REJECT_UNKNOWN; %constant int QPOL_ALLOW_UNKNOWN = SEPOL_ALLOW_UNKNOWN; %extend qpol_policy { qpol_policy(const char *path, const int options, PyObject *py_callback) { qpol_policy_t *p; if (!PyCallable_Check(py_callback)) { PyErr_SetString(PyExc_TypeError, "Callback parameter must be callable"); return NULL; } qpol_policy_open_from_file(path, &p, qpol_log_callback, (void*)py_callback, options); return p; } ~qpol_policy() { qpol_policy_destroy(&self); }; int version () { unsigned int v; (void)qpol_policy_get_policy_version(self, &v); /* only error is on null parameters neither can be here */ return (int) v; }; int handle_unknown () { unsigned int h; qpol_policy_get_policy_handle_unknown(self, &h); return h; }; /* This is whether SELinux or XEN policy */ int target_platform () { int t; (void)qpol_policy_get_target_platform(self, &t); return t; }; int capability (qpol_capability_e cap) { return qpol_policy_has_capability(self, cap); }; %newobject type_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_type_from_void) %} qpol_iterator_t *type_iter() { qpol_iterator_t *iter; if (qpol_policy_get_type_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t type_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_type_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject role_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_role_from_void) %} qpol_iterator_t *role_iter() { qpol_iterator_t *iter; if (qpol_policy_get_role_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t role_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_role_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject level_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_level_from_void) %} qpol_iterator_t *level_iter() { qpol_iterator_t *iter; if (qpol_policy_get_level_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t level_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_level_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject cat_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_cat_from_void) %} qpol_iterator_t *cat_iter() { qpol_iterator_t *iter; if (qpol_policy_get_cat_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t cat_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_cat_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject user_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_user_from_void) %} qpol_iterator_t *user_iter() { qpol_iterator_t *iter; if (qpol_policy_get_user_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t user_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_user_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject bool_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_bool_from_void) %} qpol_iterator_t *bool_iter() { qpol_iterator_t *iter; if (qpol_policy_get_bool_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t bool_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_bool_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject class_iter(char*); %pythoncode %{ @QpolGenerator(_qpol.qpol_class_from_void) %} qpol_iterator_t *class_iter(char *perm=NULL) { qpol_iterator_t *iter; if (perm) { if (qpol_perm_get_class_iter(self, perm, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get class iterator"); } } else { if (qpol_policy_get_class_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } } return iter; fail: return NULL; }; size_t class_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_class_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject common_iter(char*); %pythoncode %{ @QpolGenerator(_qpol.qpol_common_from_void) %} qpol_iterator_t *common_iter(char *perm=NULL) { qpol_iterator_t *iter; if (perm) { if (qpol_perm_get_common_iter(self, perm, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get common iterator"); } } else { if (qpol_policy_get_common_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } } return iter; fail: return NULL; }; size_t common_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_common_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject fs_use_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_fs_use_from_void) %} qpol_iterator_t *fs_use_iter() { qpol_iterator_t *iter; if (qpol_policy_get_fs_use_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t fs_use_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_fs_use_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject genfscon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_genfscon_from_void) %} qpol_iterator_t *genfscon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_genfscon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t genfscon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_genfscon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject isid_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_isid_from_void) %} qpol_iterator_t *isid_iter() { qpol_iterator_t *iter; if (qpol_policy_get_isid_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t isid_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_isid_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject netifcon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_netifcon_from_void) %} qpol_iterator_t *netifcon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_netifcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t netifcon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_netifcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject nodecon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_nodecon_from_void) %} qpol_iterator_t *nodecon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_nodecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t nodecon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_nodecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject portcon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_portcon_from_void) %} qpol_iterator_t *portcon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_portcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t portcon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_portcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject constraint_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_constraint_from_void) %} qpol_iterator_t *constraint_iter() { qpol_iterator_t *iter; if (qpol_policy_get_constraint_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t constraint_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_constraint_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject validatetrans_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_validatetrans_from_void) %} qpol_iterator_t *validatetrans_iter() { qpol_iterator_t *iter; if (qpol_policy_get_validatetrans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t validatetrans_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_validatetrans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject role_allow_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_role_allow_from_void) %} qpol_iterator_t *role_allow_iter() { qpol_iterator_t *iter; if (qpol_policy_get_role_allow_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t role_allow_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_role_allow_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject role_trans_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_role_trans_from_void) %} qpol_iterator_t *role_trans_iter() { qpol_iterator_t *iter; if (qpol_policy_get_role_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t role_trans_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_role_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject range_trans_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_range_trans_from_void) %} qpol_iterator_t *range_trans_iter() { qpol_iterator_t *iter; if (qpol_policy_get_range_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t range_trans_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_range_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject avrule_iter(int); %pythoncode %{ @QpolGenerator(_qpol.qpol_avrule_from_void) %} qpol_iterator_t *avrule_iter() { qpol_iterator_t *iter; uint32_t rule_types = QPOL_RULE_ALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT; if (qpol_policy_has_capability(self, QPOL_CAP_NEVERALLOW)) rule_types |= QPOL_RULE_NEVERALLOW; if (qpol_policy_get_avrule_iter(self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t avrule_allow_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_ALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t avrule_auditallow_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_AUDITALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t avrule_neverallow_count() { if (qpol_policy_has_capability(self, QPOL_CAP_NEVERALLOW)) { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_NEVERALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; } else { return 0; } fail: return 0; }; size_t avrule_dontaudit_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_DONTAUDIT, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject avulex_iter(int); %pythoncode %{ @QpolGenerator(_qpol.qpol_avrule_from_void) %} qpol_iterator_t *avrulex_iter() { qpol_iterator_t *iter; uint32_t rule_types = QPOL_RULE_XPERMS_ALLOW | QPOL_RULE_XPERMS_AUDITALLOW | QPOL_RULE_XPERMS_DONTAUDIT; if (qpol_policy_has_capability(self, QPOL_CAP_NEVERALLOW)) rule_types |= QPOL_RULE_XPERMS_NEVERALLOW; if (qpol_policy_get_avrule_iter(self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t avrule_allowx_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_XPERMS_ALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t avrule_auditallowx_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_XPERMS_AUDITALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t avrule_neverallowx_count() { if (qpol_policy_has_capability(self, QPOL_CAP_NEVERALLOW)) { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_XPERMS_NEVERALLOW, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; } else { return 0; } fail: return 0; }; size_t avrule_dontauditx_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_avrule_iter(self, QPOL_RULE_XPERMS_DONTAUDIT, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject terule_iter(int); %pythoncode %{ @QpolGenerator(_qpol.qpol_terule_from_void) %} qpol_iterator_t *terule_iter() { qpol_iterator_t *iter; uint32_t rule_types = QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER; if (qpol_policy_get_terule_iter(self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t terule_trans_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_terule_iter(self, QPOL_RULE_TYPE_TRANS, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t terule_change_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_terule_iter(self, QPOL_RULE_TYPE_CHANGE, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; size_t terule_member_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_terule_iter(self, QPOL_RULE_TYPE_MEMBER, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject cond_iter(); qpol_iterator_t *cond_iter() { qpol_iterator_t *iter; if (qpol_policy_get_cond_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t cond_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_cond_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject filename_trans_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_filename_trans_from_void) %} qpol_iterator_t *filename_trans_iter() { qpol_iterator_t *iter; if (qpol_policy_get_filename_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t filename_trans_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_filename_trans_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject permissive_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_type_from_void) %} qpol_iterator_t *permissive_iter() { qpol_iterator_t *iter; if (qpol_policy_get_permissive_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t permissive_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_permissive_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject typebounds_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_typebounds_from_void) %} qpol_iterator_t *typebounds_iter() { qpol_iterator_t *iter; if (qpol_policy_get_typebounds_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; %newobject polcap_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_polcap_from_void) %} qpol_iterator_t *polcap_iter() { qpol_iterator_t *iter; if (qpol_policy_get_polcap_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t polcap_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_polcap_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject default_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_default_object_from_void) %} qpol_iterator_t *default_iter() { qpol_iterator_t *iter; if (qpol_policy_get_default_object_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; %newobject iomemcon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_iomemcon_from_void) %} qpol_iterator_t *iomemcon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_iomemcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t iomemcon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_iomemcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject ioportcon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_ioportcon_from_void) %} qpol_iterator_t *ioportcon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_ioportcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t ioportcon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_ioportcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject pcidevicecon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_pcidevicecon_from_void) %} qpol_iterator_t *pcidevicecon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_pcidevicecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t pcidevicecon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_pcidevicecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject pirqcon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_pirqcon_from_void) %} qpol_iterator_t *pirqcon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_pirqcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t pirqcon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_pirqcon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; %newobject devicetreecon_iter(); %pythoncode %{ @QpolGenerator(_qpol.qpol_devicetreecon_from_void) %} qpol_iterator_t *devicetreecon_iter() { qpol_iterator_t *iter; if (qpol_policy_get_devicetreecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } return iter; fail: return NULL; }; size_t devicetreecon_count() { qpol_iterator_t *iter; size_t count = 0; if (qpol_policy_get_devicetreecon_iter(self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } qpol_iterator_get_size(iter, &count); return count; fail: return 0; }; }; /* qpol iterator */ typedef struct qpol_iterator {} qpol_iterator_t; %extend qpol_iterator { /* user never directly creates, but SWIG expects a constructor */ qpol_iterator() { SWIG_exception(SWIG_TypeError, "User may not create iterators directly"); fail: return NULL; }; ~qpol_iterator() { qpol_iterator_destroy(&self); }; void *item() { void *i; if (qpol_iterator_get_item(self, &i)) { SWIG_exception(SWIG_RuntimeError, "Could not get item"); } return i; fail: return NULL; }; void next_() { if (qpol_iterator_next(self)) { SWIG_exception(SWIG_RuntimeError, "Error advancing iterator"); } fail: return; }; int isend() { return qpol_iterator_end(self); }; size_t size() { size_t s; if (qpol_iterator_get_size(self, &s)) { SWIG_exception(SWIG_ValueError, "Could not get iterator size"); } return s; fail: return 0; }; }; /* qpol type */ typedef struct qpol_type {} qpol_type_t; %extend qpol_type { %exception qpol_type { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Invalid type or attribute."); return NULL; } } qpol_type(qpol_policy_t *p, const char *name) { const qpol_type_t *t; qpol_policy_get_type_by_name(p, name, &t); return (qpol_type_t*)t; }; ~qpol_type() { /* no op */ return; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_type_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get type name"); } return name; fail: return NULL; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_type_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get type value"); } fail: return (int) v; }; int isalias(qpol_policy_t *p) { unsigned char i; if (qpol_type_get_isalias(p, self, &i)) { SWIG_exception(SWIG_ValueError, "Could not determine whether type is an alias"); } fail: return (int)i; }; int isattr(qpol_policy_t *p) { unsigned char i; if (qpol_type_get_isattr(p, self, &i)) { SWIG_exception(SWIG_ValueError, "Could not determine whether type is an attribute"); } fail: return (int)i; }; int ispermissive(qpol_policy_t *p) { unsigned char i; if (qpol_type_get_ispermissive(p, self, &i)) { SWIG_exception(SWIG_ValueError, "Could not determine whether type is permissive"); } fail: return (int)i; }; %newobject type_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_type_from_void) %} qpol_iterator_t *type_iter(qpol_policy_t *p) { qpol_iterator_t *iter; int retv = qpol_type_get_type_iter(p, self, &iter); if (retv < 0) { SWIG_exception(SWIG_RuntimeError, "Could not get attribute types"); } else if (retv > 0) { SWIG_exception(SWIG_TypeError, "Type is not an attribute"); } fail: return iter; }; %newobject attr_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_type_from_void) %} qpol_iterator_t *attr_iter(qpol_policy_t *p) { qpol_iterator_t *iter; int retv = qpol_type_get_attr_iter(p, self, &iter); if (retv < 0) { SWIG_exception(SWIG_RuntimeError, "Could not get type attributes"); } else if (retv > 0) { SWIG_exception(SWIG_TypeError, "Type is an attribute"); } fail: return iter; }; %newobject alias_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *alias_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_type_get_alias_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get type aliases"); } fail: return iter; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_permissive_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get permissive type name"); } return name; fail: return NULL; }; }; %inline %{ qpol_type_t *qpol_type_from_void(void *x) { return (qpol_type_t*)x; } %} /* qpol role */ typedef struct qpol_role {} qpol_role_t; %extend qpol_role { %exception qpol_role { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Invalid type or attribute."); return NULL; } } qpol_role(qpol_policy_t *p, const char *name) { const qpol_role_t *r; qpol_policy_get_role_by_name(p, name, &r); return (qpol_role_t*)r; }; ~qpol_role() { /* no op */ return; }; int value (qpol_policy_t *p) { uint32_t v; if (qpol_role_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get role value"); } fail: return (int) v; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_role_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get role name"); } return name; fail: return NULL; }; %newobject type_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_type_from_void) %} qpol_iterator_t *type_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_role_get_type_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get role types"); } fail: return iter; }; %newobject dominate_iter(qpol_policy_t*); qpol_iterator_t *dominate_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_role_get_dominate_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get dominated roles"); } fail: return iter; }; }; %inline %{ qpol_role_t *qpol_role_from_void(void *x) { return (qpol_role_t*)x; } %} /* qpol level */ typedef struct qpol_level {} qpol_level_t; %extend qpol_level { %exception qpol_level { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid level."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_level(qpol_policy_t *p, const char *name) { const qpol_level_t *l; qpol_policy_get_level_by_name(p, name, &l); return (qpol_level_t*)l; }; ~qpol_level() { /* no op */ return; }; int isalias(qpol_policy_t *p) { unsigned char i; if (qpol_level_get_isalias(p, self, &i)) { SWIG_exception(SWIG_ValueError, "Could not determine whether level is an alias"); } fail: return (int)i; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_level_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get level sensitivity value"); } fail: return (int) v; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_level_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get level sensitivity name"); } return name; fail: return NULL; }; %newobject cat_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_cat_from_void) %} qpol_iterator_t *cat_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_level_get_cat_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get level categories"); } fail: return iter; }; %newobject alias_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *alias_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_level_get_alias_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get level aliases"); } fail: return iter; }; }; %inline %{ qpol_level_t *qpol_level_from_void(void *x) { return (qpol_level_t*)x; } %} /* qpol cat */ typedef struct qpol_cat {} qpol_cat_t; %extend qpol_cat { %exception qpol_cat { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid category."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_cat(qpol_policy_t *p, const char *name) { const qpol_cat_t *c; qpol_policy_get_cat_by_name(p, name, &c); return (qpol_cat_t*)c; }; ~qpol_cat() { /* no op */ return; }; int isalias(qpol_policy_t *p) { unsigned char i; if (qpol_cat_get_isalias(p, self, &i)) { SWIG_exception(SWIG_ValueError, "Could not determine whether category is an alias"); } fail: return (int)i; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_cat_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get category value"); } fail: return (int) v; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_cat_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get category name"); } return name; fail: return NULL; }; %newobject alias_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *alias_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_cat_get_alias_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get category aliases"); } fail: return iter; }; }; %inline %{ qpol_cat_t *qpol_cat_from_void(void *x) { return (qpol_cat_t*)x; } %} /* qpol mls range */ typedef struct qpol_mls_range {} qpol_mls_range_t; %extend qpol_mls_range { /* * TODO: determine how to conditionally destroy this range. * It should only be destroyed if it was looked up (user-entered) * Otherwise qpol will destroy the others when the policy closes. */ %exception qpol_mls_range { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid range."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_mls_range(qpol_policy_t *p, qpol_mls_level_t *l, qpol_mls_level_t *h) { qpol_mls_range_t *range; qpol_policy_get_mls_range_from_mls_levels(p, l, h, &range); return range; } ~qpol_mls_range() { /* no op */ return; }; const qpol_mls_level_t *high_level(qpol_policy_t *p) { const qpol_mls_level_t *l; if (qpol_mls_range_get_high_level(p, self, &l)) { SWIG_exception(SWIG_ValueError, "Could not get range high levl"); } fail: return l; }; const qpol_mls_level_t *low_level(qpol_policy_t *p) { const qpol_mls_level_t *l; if (qpol_mls_range_get_low_level(p, self, &l)) { SWIG_exception(SWIG_ValueError, "Could not get range low levl"); } fail: return l; }; }; %inline %{ qpol_mls_range_t *qpol_mls_range_from_void(void *x) { return (qpol_mls_range_t*)x; } %} /* qpol semantic mls level */ typedef struct qpol_semantic_level {} qpol_semantic_level_t; %extend qpol_semantic_level { %exception qpol_semantic_level { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Invalid sensitivity name."); return NULL; } } qpol_semantic_level(qpol_policy_t *p, const char *name) { const qpol_semantic_level_t *l; qpol_policy_get_semantic_level_by_name(p, name, &l); return (qpol_semantic_level_t*)l; }; ~qpol_semantic_level() { qpol_semantic_level_destroy(self); return; }; %exception add_cats { $action if (result) { PyErr_SetString(PyExc_ValueError, "Invalid category name or category range."); return NULL; } } int add_cats(qpol_policy_t *p, const char *low, const char *high) { return qpol_semantic_level_add_cats_by_name(p, self, low, high); } }; /* qpol mls level */ typedef struct qpol_mls_level {} qpol_mls_level_t; %extend qpol_mls_level { %exception qpol_mls_level { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Invalid level."); return NULL; } } qpol_mls_level(qpol_policy_t *p, qpol_semantic_level_t *l) { qpol_mls_level_t *level; qpol_mls_level_from_semantic_level(p, l, &level); return level; } ~qpol_mls_level() { /* no op */ return; }; const char *sens_name(qpol_policy_t *p) { const char *name; if (qpol_mls_level_get_sens_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get level sensitivity name"); } fail: return name; }; %newobject cat_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_cat_from_void) %} qpol_iterator_t *cat_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_mls_level_get_cat_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get level categories"); } fail: return iter; }; }; %inline %{ qpol_mls_level_t *qpol_mls_level_from_void(void *x) { return (qpol_mls_level_t*)x; } %} /* qpol user */ typedef struct qpol_user {} qpol_user_t; %extend qpol_user { %exception qpol_user { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Invalid user."); return NULL; } } qpol_user(qpol_policy_t *p, const char *name) { const qpol_user_t *u; qpol_policy_get_user_by_name(p, name, &u); return (qpol_user_t*)u; }; ~qpol_user() { /* no op */ return; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_user_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get user value"); } fail: return (int) v; }; %newobject role_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_role_from_void) %} qpol_iterator_t *role_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_user_get_role_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of Memory"); } fail: return iter; }; const qpol_mls_range_t *range(qpol_policy_t *p) { const qpol_mls_range_t *r; if (qpol_user_get_range(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get user range"); } fail: return r; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_user_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get user name"); } fail: return name; }; const qpol_mls_level_t *dfltlevel(qpol_policy_t *p) { const qpol_mls_level_t *l; if (qpol_user_get_dfltlevel(p, self, &l)) { SWIG_exception(SWIG_ValueError, "Could not get user default level"); } fail: return l; }; }; %inline %{ qpol_user_t *qpol_user_from_void(void *x) { return (qpol_user_t*)x; } %} /* qpol bool */ typedef struct qpol_bool {} qpol_bool_t; %extend qpol_bool { qpol_bool(qpol_policy_t *p, const char *name) { qpol_bool_t *b; if (qpol_policy_get_bool_by_name(p, name, &b)) { SWIG_exception(SWIG_RuntimeError, "Boolean does not exist"); } fail: return b; }; ~qpol_bool() { /* no op */ return; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_bool_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get boolean value"); } fail: return (int) v; }; int state(qpol_policy_t *p) { int s; if (qpol_bool_get_state(p, self, &s)) { SWIG_exception(SWIG_ValueError, "Could not get boolean state"); } fail: return s; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_bool_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get boolean name"); } fail: return name; }; }; %inline %{ qpol_bool_t *qpol_bool_from_void(void *x) { return (qpol_bool_t*)x; } %} /* qpol context */ typedef struct qpol_context {} qpol_context_t; %extend qpol_context { qpol_context() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_context_t objects"); fail: return NULL; }; ~qpol_context() { /* no op */ return; }; const qpol_user_t *user(qpol_policy_t *p) { const qpol_user_t *u; if (qpol_context_get_user(p, self, &u)) { SWIG_exception(SWIG_ValueError, "Could not get user from context"); } fail: return u; }; const qpol_role_t *role(qpol_policy_t *p) { const qpol_role_t *r; if (qpol_context_get_role(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get role from context"); } fail: return r; }; const qpol_type_t *type_(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_context_get_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get type from context"); } fail: return t; }; const qpol_mls_range_t *range(qpol_policy_t *p) { const qpol_mls_range_t *r; if (qpol_context_get_range(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get range from context"); } fail: return r; }; }; %inline %{ qpol_context_t *qpol_context_from_void(void *x) { return (qpol_context_t*)x; } %} /* qpol class */ typedef struct qpol_class {} qpol_class_t; %extend qpol_class { %exception qpol_class { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid class."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_class(qpol_policy_t *p, const char *name) { const qpol_class_t *c; qpol_policy_get_class_by_name(p, name, &c); return (qpol_class_t*)c; }; ~qpol_class() { /* no op */ return; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_class_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get value for class"); } fail: return (int) v; }; %exception common { $action if (!result) { PyErr_SetString(PyExc_ValueError, "Class does not inherit a common."); return NULL; } } const qpol_common_t *common(qpol_policy_t *p) { const qpol_common_t *c; if(qpol_class_get_common(p, self, &c)) { SWIG_exception(SWIG_ValueError, "Could not get common for class"); } fail: return c; }; %newobject perm_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *perm_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if(qpol_class_get_perm_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get class permissions"); } fail: return iter; }; %newobject constraint_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_constraint_from_void) %} qpol_iterator_t *constraint_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if(qpol_class_get_constraint_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get class constraints"); } fail: return iter; }; %newobject validatetrans_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_validatetrans_from_void) %} qpol_iterator_t *validatetrans_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if(qpol_class_get_validatetrans_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get class validatetrans statements"); } fail: return iter; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_class_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get class name"); } fail: return name; }; }; %inline %{ qpol_class_t *qpol_class_from_void(void *x) { return (qpol_class_t*)x; } %} /* qpol common */ typedef struct qpol_common {} qpol_common_t; %extend qpol_common { %exception qpol_common { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid common."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_common(qpol_policy_t *p, const char *name) { const qpol_common_t *c; qpol_policy_get_common_by_name(p, name, &c); return (qpol_common_t*)c; }; ~qpol_common() { /* no op */ return; }; int value(qpol_policy_t *p) { uint32_t v; if (qpol_common_get_value(p, self, &v)) { SWIG_exception(SWIG_ValueError, "Could not get value for common"); } fail: return (int) v; }; %newobject perm_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *perm_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if(qpol_common_get_perm_iter(p, self, &iter)) { SWIG_exception(SWIG_RuntimeError, "Could not get common permissions"); } fail: return iter; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_common_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get common name"); } fail: return name; }; }; %inline %{ qpol_common_t *qpol_common_from_void(void *x) { return (qpol_common_t*)x; } %} /* qpol fs_use */ /* The defines QPOL_FS_USE_XATTR through QPOL_FS_USE_NONE are * copied from sepol/policydb/services.h. * QPOL_FS_USE_PSID is an extension to support v12 policies. */ #define QPOL_FS_USE_XATTR 1U #define QPOL_FS_USE_TRANS 2U #define QPOL_FS_USE_TASK 3U #define QPOL_FS_USE_GENFS 4U #define QPOL_FS_USE_NONE 5U #define QPOL_FS_USE_PSID 6U typedef struct qpol_fs_use {} qpol_fs_use_t; %extend qpol_fs_use { qpol_fs_use(qpol_policy_t *p, const char *name) { const qpol_fs_use_t *f; if (qpol_policy_get_fs_use_by_name(p, name, &f)) { SWIG_exception(SWIG_RuntimeError, "FS Use Statement does not exist"); } fail: return (qpol_fs_use_t*)f; }; ~qpol_fs_use() { /* no op */ return; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_fs_use_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get file system name"); } fail: return name; }; int behavior(qpol_policy_t *p) { uint32_t behav; if (qpol_fs_use_get_behavior(p, self, &behav)) { SWIG_exception(SWIG_ValueError, "Could not get file system labeling behavior"); } fail: return (int) behav; }; const qpol_context_t *context(qpol_policy_t *p) { uint32_t behav; const qpol_context_t *ctx = NULL; qpol_fs_use_get_behavior(p, self, &behav); if (behav == QPOL_FS_USE_PSID) { SWIG_exception(SWIG_TypeError, "Cannot get context for fs_use_psid statements"); } else if (qpol_fs_use_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get file system context"); } fail: return ctx; }; }; %inline %{ qpol_fs_use_t *qpol_fs_use_from_void(void *x) { return (qpol_fs_use_t*)x; } %} /* qpol genfscon */ /* values from flask do not change */ #define QPOL_CLASS_ALL 0U #define QPOL_CLASS_BLK_FILE 11U #define QPOL_CLASS_CHR_FILE 10U #define QPOL_CLASS_DIR 7U #define QPOL_CLASS_FIFO_FILE 13U #define QPOL_CLASS_FILE 6U #define QPOL_CLASS_LNK_FILE 9U #define QPOL_CLASS_SOCK_FILE 12U typedef struct qpol_genfscon {} qpol_genfscon_t; %extend qpol_genfscon { qpol_genfscon(qpol_policy_t *p, const char *name, const char *path) { qpol_genfscon_t *g; if (qpol_policy_get_genfscon_by_name(p, name, path, &g)) { SWIG_exception(SWIG_RuntimeError, "Genfscon statement does not exist"); } fail: return g; }; ~qpol_genfscon() { free(self); }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_genfscon_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get file system name"); } fail: return name; }; const char *path(qpol_policy_t *p) { const char *path; if (qpol_genfscon_get_path(p, self, &path)) { SWIG_exception(SWIG_ValueError, "Could not get file system path"); } fail: return path; }; unsigned int object_class(qpol_policy_t *p) { uint32_t cls; if (qpol_genfscon_get_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get genfscon statement class"); } switch (cls) { case QPOL_CLASS_BLK_FILE: return S_IFBLK; case QPOL_CLASS_CHR_FILE: return S_IFCHR; case QPOL_CLASS_DIR: return S_IFDIR; case QPOL_CLASS_FIFO_FILE: return S_IFIFO; case QPOL_CLASS_FILE: return S_IFREG; case QPOL_CLASS_LNK_FILE: return S_IFLNK; case QPOL_CLASS_SOCK_FILE: return S_IFSOCK; default: return 0; /* all file types */ } fail: return 0; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_genfscon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for genfscon statement"); } fail: return ctx; }; }; %inline %{ qpol_genfscon_t *qpol_genfscon_from_void(void *x) { return (qpol_genfscon_t*)x; } %} /* qpol isid */ typedef struct qpol_isid {} qpol_isid_t; %extend qpol_isid { %exception qpol_isid { $action if (!result) { if (errno == EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid initial sid name."); } else { PyErr_SetFromErrno(PyExc_OSError); } return NULL; } } qpol_isid(qpol_policy_t *p, const char *name) { const qpol_isid_t *i; qpol_policy_get_isid_by_name(p, name, &i); return (qpol_isid_t*)i; }; ~qpol_isid() { /* no op */ return; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_isid_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get name for initial sid"); } fail: return name; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_isid_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for initial sid"); } fail: return ctx; }; }; %inline %{ qpol_isid_t *qpol_isid_from_void(void *x) { return (qpol_isid_t*)x; } %} /* qpol netifcon */ typedef struct qpol_netifcon {} qpol_netifcon_t; %extend qpol_netifcon { qpol_netifcon(qpol_policy_t *p, const char *name) { const qpol_netifcon_t *n; if (qpol_policy_get_netifcon_by_name(p, name, &n)) { SWIG_exception(SWIG_RuntimeError, "Netifcon statement does not exist"); } fail: return (qpol_netifcon_t*)n; }; ~qpol_netifcon() { /* no op */ return; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_netifcon_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get name for netifcon statement"); } fail: return name; }; const qpol_context_t *msg_con(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_netifcon_get_msg_con(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get message context for netifcon statement"); } fail: return ctx; }; const qpol_context_t *if_con(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_netifcon_get_if_con(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get interface context for netifcon statement"); } fail: return ctx; }; }; %inline %{ qpol_netifcon_t *qpol_netifcon_from_void(void *x) { return (qpol_netifcon_t*)x; } %} /* qpol nodecon */ #define QPOL_IPV4 0 #define QPOL_IPV6 1 typedef struct qpol_nodecon {} qpol_nodecon_t; %extend qpol_nodecon { qpol_nodecon(qpol_policy_t *p, int addr[4], int mask[4], int protocol) { uint32_t a[4], m[4]; qpol_nodecon_t *n; a[0] = (uint32_t) addr[0]; a[1] = (uint32_t) addr[1]; a[2] = (uint32_t) addr[2]; a[3] = (uint32_t) addr[3]; m[0] = (uint32_t) mask[0]; m[1] = (uint32_t) mask[1]; m[2] = (uint32_t) mask[2]; m[3] = (uint32_t) mask[3]; if (qpol_policy_get_nodecon_by_node(p, a, m, protocol, &n)) { SWIG_exception(SWIG_RuntimeError, "Nodecon statement does not exist"); } fail: return n; } ~qpol_nodecon() { free(self); }; char *addr(qpol_policy_t *p) { uint32_t *a; unsigned char proto; char *addr = NULL; addr = malloc(INET6_ADDRSTRLEN * sizeof(char)); if(!addr) SWIG_exception(SWIG_MemoryError, "Out of memory"); if (qpol_nodecon_get_addr(p, self, &a, &proto)) { SWIG_exception(SWIG_ValueError, "Could not get address of nodecon statement"); } if(proto == QPOL_IPV4) { inet_ntop(AF_INET, a, addr, INET6_ADDRSTRLEN); } else { inet_ntop(AF_INET6, a, addr, INET6_ADDRSTRLEN); } fail: return addr; }; char *mask(qpol_policy_t *p) { uint32_t *m; unsigned char proto; char *mask; mask = malloc(INET6_ADDRSTRLEN * sizeof(char)); if (!mask) SWIG_exception(SWIG_MemoryError, "Out of memory"); if (qpol_nodecon_get_mask(p, self, &m, &proto)) { SWIG_exception(SWIG_ValueError, "Could not get mask of nodecon statement"); } if(proto == QPOL_IPV4) { inet_ntop(AF_INET, m, mask, INET6_ADDRSTRLEN); } else { inet_ntop(AF_INET6, m, mask, INET6_ADDRSTRLEN); } fail: return mask; }; int protocol(qpol_policy_t *p) { unsigned char proto; if (qpol_nodecon_get_protocol(p, self, &proto)) { SWIG_exception(SWIG_ValueError, "Could not get protocol for nodecon statement"); } fail: if(proto == QPOL_IPV4) { return AF_INET; } else { return AF_INET6; } }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_nodecon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for nodecon statement"); } fail: return ctx; }; }; %inline %{ qpol_nodecon_t *qpol_nodecon_from_void(void *x) { return (qpol_nodecon_t*)x; } %} /* qpol portcon */ /* from netinet/in.h */ #define IPPROTO_TCP 6 #define IPPROTO_UDP 17 typedef struct qpol_portcon {} qpol_portcon_t; %extend qpol_portcon { qpol_portcon(qpol_policy_t *p, uint16_t low, uint16_t high, uint8_t protocol) { const qpol_portcon_t *qp; if (qpol_policy_get_portcon_by_port(p, low, high, protocol, &qp)) { SWIG_exception(SWIG_RuntimeError, "Portcon statement does not exist"); } fail: return (qpol_portcon_t*)qp; }; ~qpol_portcon() { /* no op */ return; }; uint16_t low_port(qpol_policy_t *p) { uint16_t port = 0; if(qpol_portcon_get_low_port(p, self, &port)) { SWIG_exception(SWIG_RuntimeError, "Could not get low port for portcon statement"); } fail: return port; }; uint16_t high_port(qpol_policy_t *p) { uint16_t port = 0; if(qpol_portcon_get_high_port(p, self, &port)) { SWIG_exception(SWIG_RuntimeError, "Could not get high port for portcon statement"); } fail: return port; }; uint8_t protocol(qpol_policy_t *p) { uint8_t proto = 0; if (qpol_portcon_get_protocol(p, self, &proto)) { SWIG_exception(SWIG_RuntimeError, "Could not get protocol for portcon statement"); } fail: return proto; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_portcon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for portcon statement"); } fail: return ctx; }; } %inline %{ qpol_portcon_t *qpol_portcon_from_void(void *x) { return (qpol_portcon_t*)x; } %} /* qpol constraint */ typedef struct qpol_constraint {} qpol_constraint_t; %extend qpol_constraint { qpol_constraint() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_constraint_t objects"); fail: return NULL; }; ~qpol_constraint() { free(self); }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_constraint_get_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for constraint"); } fail: return cls; }; %newobject perm_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *perm_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_constraint_get_perm_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; %newobject expr_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_constraint_expr_node_from_void) %} qpol_iterator_t *expr_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_constraint_get_expr_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; }; %inline %{ qpol_constraint_t *qpol_constraint_from_void(void *x) { return (qpol_constraint_t*)x; } %} /* qpol validatetrans */ typedef struct qpol_validatetrans {} qpol_validatetrans_t; %extend qpol_validatetrans { qpol_validatetrans() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_validatetrans_t objects"); fail: return NULL; }; ~qpol_validatetrans() { free(self); }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_validatetrans_get_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for validatetrans"); } fail: return cls; }; %newobject expr_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_constraint_expr_node_from_void) %} qpol_iterator_t *expr_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_validatetrans_get_expr_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; }; %inline %{ qpol_validatetrans_t *qpol_validatetrans_from_void(void *x) { return (qpol_validatetrans_t*)x; } %} /* qpol constraint expression node */ /* expr_type values */ #define QPOL_CEXPR_TYPE_NOT 1 #define QPOL_CEXPR_TYPE_AND 2 #define QPOL_CEXPR_TYPE_OR 3 #define QPOL_CEXPR_TYPE_ATTR 4 #define QPOL_CEXPR_TYPE_NAMES 5 /* symbol type values */ #define QPOL_CEXPR_SYM_USER 1 #define QPOL_CEXPR_SYM_ROLE 2 #define QPOL_CEXPR_SYM_TYPE 4 #define QPOL_CEXPR_SYM_TARGET 8 #define QPOL_CEXPR_SYM_XTARGET 16 #define QPOL_CEXPR_SYM_L1L2 32 #define QPOL_CEXPR_SYM_L1H2 64 #define QPOL_CEXPR_SYM_H1L2 128 #define QPOL_CEXPR_SYM_H1H2 256 #define QPOL_CEXPR_SYM_L1H1 512 #define QPOL_CEXPR_SYM_L2H2 1024 /* op values */ #define QPOL_CEXPR_OP_EQ 1 #define QPOL_CEXPR_OP_NEQ 2 #define QPOL_CEXPR_OP_DOM 3 #define QPOL_CEXPR_OP_DOMBY 4 #define QPOL_CEXPR_OP_INCOMP 5 typedef struct qpol_constraint_expr_node {} qpol_constraint_expr_node_t; %extend qpol_constraint_expr_node { qpol_constraint_expr_node() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_constraint_expr_node_t objects"); fail: return NULL; }; ~qpol_constraint_expr_node() { /* no op */ return; }; int expr_type(qpol_policy_t *p) { uint32_t et; if (qpol_constraint_expr_node_get_expr_type(p, self, &et)) { SWIG_exception(SWIG_ValueError, "Could not get expression type for node"); } fail: return (int) et; }; int sym_type(qpol_policy_t *p) { uint32_t st; if (qpol_constraint_expr_node_get_sym_type(p, self, &st)) { SWIG_exception(SWIG_ValueError, "Could not get symbol type for node"); } fail: return (int) st; }; int op(qpol_policy_t *p) { uint32_t op; if (qpol_constraint_expr_node_get_op(p, self, &op)) { SWIG_exception(SWIG_ValueError, "Could not get operator for node"); } fail: return (int) op; }; %newobject names_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *names_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_constraint_expr_node_get_names_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; }; %inline %{ qpol_constraint_expr_node_t *qpol_constraint_expr_node_from_void(void *x) { return (qpol_constraint_expr_node_t*)x; } %} /* qpol role allow */ typedef struct qpol_role_allow {} qpol_role_allow_t; %extend qpol_role_allow { qpol_role_allow() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_role_allow_t objects"); fail: return NULL; }; ~qpol_role_allow() { /* no op */ return; }; %pythoncode %{ def rule_type(self,policy): return "allow" %} const qpol_role_t *source_role(qpol_policy_t *p) { const qpol_role_t *r; if (qpol_role_allow_get_source_role(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get source for role allow rule"); } fail: return r; }; const qpol_role_t *target_role(qpol_policy_t *p) { const qpol_role_t *r; if (qpol_role_allow_get_target_role(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get target for role allow rule"); } fail: return r; }; }; %inline %{ qpol_role_allow_t *qpol_role_allow_from_void(void *x) { return (qpol_role_allow_t*)x; } %} /* qpol role trans */ typedef struct qpol_role_trans {} qpol_role_trans_t; %extend qpol_role_trans { qpol_role_trans() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_role_trans_t objects"); fail: return NULL; }; ~qpol_role_trans() { /* no op */ return; }; %pythoncode %{ def rule_type(self,policy): return "role_transition" %} const qpol_role_t *source_role(qpol_policy_t *p) { const qpol_role_t *r; if (qpol_role_trans_get_source_role(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get source for role_transition rule"); } fail: return r; }; const qpol_type_t *target_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_role_trans_get_target_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get target for role_transition rule"); } fail: return t; }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *c; if (qpol_role_trans_get_object_class(p, self, &c)) { SWIG_exception(SWIG_ValueError, "Could not get class for role_transition rule"); } fail: return c; }; const qpol_role_t *default_role(qpol_policy_t *p) { const qpol_role_t *r; if (qpol_role_trans_get_default_role(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get default for role_transition rule"); } fail: return r; }; }; %inline %{ qpol_role_trans_t *qpol_role_trans_from_void(void *x) { return (qpol_role_trans_t*)x; } %} /* qpol range trans */ typedef struct qpol_range_trans {} qpol_range_trans_t; %extend qpol_range_trans { qpol_range_trans() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_range_trans_t objects"); fail: return NULL; }; ~qpol_range_trans() { /* no op */ return; }; %pythoncode %{ def rule_type(self,policy): return "range_transition" %} const qpol_type_t *source_type (qpol_policy_t *p) { const qpol_type_t *t; if (qpol_range_trans_get_source_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get source for range_transition rule"); } fail: return t; }; const qpol_type_t *target_type (qpol_policy_t *p) { const qpol_type_t *t; if (qpol_range_trans_get_target_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get target for range_transition rule"); } fail: return t; }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_range_trans_get_target_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for range_transition rule"); } fail: return cls; }; const qpol_mls_range_t *range(qpol_policy_t *p) { const qpol_mls_range_t *r; if (qpol_range_trans_get_range(p, self, &r)) { SWIG_exception(SWIG_ValueError, "Could not get range for range_transition rule"); } fail: return r; }; }; %inline %{ qpol_range_trans_t *qpol_range_trans_from_void(void *x) { return (qpol_range_trans_t*)x; } %} /* qpol av rule */ #define QPOL_RULE_ALLOW 0x0001 #define QPOL_RULE_NEVERALLOW 0x0080 #define QPOL_RULE_AUDITALLOW 0x0002 #define QPOL_RULE_DONTAUDIT 0x0004 #define QPOL_RULE_XPERMS_ALLOW 0x0100 #define QPOL_RULE_XPERMS_AUDITALLOW 0x0200 #define QPOL_RULE_XPERMS_DONTAUDIT 0x0400 #define QPOL_RULE_XPERMS_NEVERALLOW 0x0800 typedef struct qpol_avrule {} qpol_avrule_t; %extend qpol_avrule { qpol_avrule() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_avrule_t objects"); fail: return NULL; }; ~qpol_avrule() { /* no op */ return; }; uint32_t rule_type(qpol_policy_t *p) { uint32_t rt; if (qpol_avrule_get_rule_type(p, self, &rt)) { SWIG_exception(SWIG_ValueError, "Could not get rule type for av rule"); } return rt; fail: return 0; }; const qpol_type_t *source_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_avrule_get_source_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get source for av rule"); } fail: return t; }; const qpol_type_t *target_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_avrule_get_target_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get target for av rule"); } fail: return t; }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_avrule_get_object_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for av rule"); } fail: return cls; }; %newobject perm_iter(qpol_policy_t *p); %pythoncode %{ @QpolGenerator(_qpol.to_str) %} qpol_iterator_t *perm_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_avrule_get_perm_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; /* TODO, do I need an exception (similar to cond) that is thrown if you ask this on a non extended avrule? Likewise for asking for prems an an extended rule */ %newobject xperm_iter(qpol_policy_t *p); %pythoncode %{ @QpolGenerator(_qpol.to_int_with_free) %} qpol_iterator_t *xperm_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_avrule_get_xperm_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; int is_extended(qpol_policy_t *p) { uint32_t e; if (qpol_avrule_get_is_extended(p, self, &e)) { SWIG_exception(SWIG_ValueError, "Could not determine if av rule is extended"); } fail: return (int) e; }; const char * xperm_type(qpol_policy_t *p) { char *xt; if (qpol_avrule_get_xperm_type(p, self, &xt)) { SWIG_exception(SWIG_ValueError, "Could not get xperm type for av rule"); } fail: return xt; }; %exception cond { $action if (!result) { PyErr_SetString(PyExc_AttributeError, "Rule is not conditional."); return NULL; } } const qpol_cond_t *cond(qpol_policy_t *p) { const qpol_cond_t *c; qpol_avrule_get_cond(p, self, &c); return c; }; int is_enabled(qpol_policy_t *p) { uint32_t e; if (qpol_avrule_get_is_enabled(p, self, &e)) { SWIG_exception(SWIG_ValueError, "Could not determine if av rule is enabled"); } fail: return (int) e; }; %exception which_list { $action if (result < 0) { PyErr_SetString(PyExc_AttributeError, "Rule is not conditional."); return NULL; } } int which_list(qpol_policy_t *p) { const qpol_cond_t *c; uint32_t which = 0; qpol_avrule_get_cond(p, self, &c); if (c == NULL) { return -1; } else if (qpol_avrule_get_which_list(p, self, &which)) { return -1; } return (int) which; }; }; %inline %{ qpol_avrule_t *qpol_avrule_from_void(void *x) { return (qpol_avrule_t*)x; } %} /* qpol te rule */ #define QPOL_RULE_TYPE_TRANS 16 #define QPOL_RULE_TYPE_CHANGE 64 #define QPOL_RULE_TYPE_MEMBER 32 typedef struct qpol_terule {} qpol_terule_t; %extend qpol_terule { qpol_terule() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_terule_t objects"); fail: return NULL; }; ~qpol_terule() { /* no op */ return; }; uint32_t rule_type(qpol_policy_t *p) { uint32_t rt; if (qpol_terule_get_rule_type(p, self, &rt)) { SWIG_exception(SWIG_ValueError, "Could not get rule type for te rule"); } return rt; fail: return 0; }; const qpol_type_t *source_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_terule_get_source_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get source for te rule"); } fail: return t; }; const qpol_type_t *target_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_terule_get_target_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get target for te rule"); } fail: return t; }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_terule_get_object_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for te rule"); } fail: return cls; }; const qpol_type_t *default_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_terule_get_default_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get default for te rule"); } fail: return t; }; %exception cond { $action if (!result) { PyErr_SetString(PyExc_AttributeError, "Rule is not conditional."); return NULL; } } const qpol_cond_t *cond(qpol_policy_t *p) { const qpol_cond_t *c; qpol_terule_get_cond(p, self, &c); return c; }; int is_enabled(qpol_policy_t *p) { uint32_t e; if (qpol_terule_get_is_enabled(p, self, &e)) { SWIG_exception(SWIG_ValueError, "Could not determine if te rule is enabled"); } fail: return (int) e; }; %exception which_list { $action if (result < 0) { PyErr_SetString(PyExc_AttributeError, "Rule is not conditional."); return NULL; } } int which_list(qpol_policy_t *p) { const qpol_cond_t *c; uint32_t which = 0; qpol_terule_get_cond(p, self, &c); if (c == NULL) { return -1; } else if (qpol_terule_get_which_list(p, self, &which)) { return -1; } return (int) which; }; }; %inline %{ qpol_terule_t *qpol_terule_from_void(void *x) { return (qpol_terule_t*)x; } %} /* qpol conditional */ typedef struct qpol_cond {} qpol_cond_t; %extend qpol_cond { qpol_cond() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_cond_t objects"); fail: return NULL; }; ~qpol_cond() { /* no op */ return; }; %newobject expr_node_iter(qpol_policy_t*); %pythoncode %{ @QpolGenerator(_qpol.qpol_cond_expr_node_from_void) %} qpol_iterator_t *expr_node_iter(qpol_policy_t *p) { qpol_iterator_t *iter; if (qpol_cond_get_expr_node_iter(p, self, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; %newobject av_true_iter(qpol_policy_t*, int); qpol_iterator_t *av_true_iter(qpol_policy_t *p, int rule_types) { qpol_iterator_t *iter; if (qpol_cond_get_av_true_iter(p, self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; %newobject av_false_iter(qpol_policy_t*, int); qpol_iterator_t *av_false_iter(qpol_policy_t *p, int rule_types) { qpol_iterator_t *iter; if (qpol_cond_get_av_false_iter(p, self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; %newobject te_true_iter(qpol_policy_t*, int); qpol_iterator_t *te_true_iter(qpol_policy_t *p, int rule_types) { qpol_iterator_t *iter; if (qpol_cond_get_te_true_iter(p, self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; %newobject te_false_iter(qpol_policy_t*, int); qpol_iterator_t *te_false_iter(qpol_policy_t *p, int rule_types) { qpol_iterator_t *iter; if (qpol_cond_get_te_false_iter(p, self, rule_types, &iter)) { SWIG_exception(SWIG_MemoryError, "Out of memory"); } fail: return iter; }; int evaluate(qpol_policy_t *p) { uint32_t e; if (qpol_cond_eval(p, self, &e)) { SWIG_exception(SWIG_RuntimeError, "Could not evaluate conditional"); } fail: return (int) e; }; }; %inline %{ qpol_cond_t *qpol_cond_from_void(void *x) { return (qpol_cond_t*)x; } %} /* qpol conditional expression node */ #define QPOL_COND_EXPR_BOOL 1 /* plain bool */ #define QPOL_COND_EXPR_NOT 2 /* !bool */ #define QPOL_COND_EXPR_OR 3 /* bool || bool */ #define QPOL_COND_EXPR_AND 4 /* bool && bool */ #define QPOL_COND_EXPR_XOR 5 /* bool ^ bool */ #define QPOL_COND_EXPR_EQ 6 /* bool == bool */ #define QPOL_COND_EXPR_NEQ 7 /* bool != bool */ typedef struct qpol_cond_expr_node {} qpol_cond_expr_node_t; %extend qpol_cond_expr_node { qpol_cond_expr_node() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_cond_expr_node_t objects"); fail: return NULL; }; ~qpol_cond_expr_node() { /* no op */ return; }; int expr_type(qpol_policy_t *p) { uint32_t et; if (qpol_cond_expr_node_get_expr_type(p, self, &et)) { SWIG_exception(SWIG_ValueError, "Could not get node expression type"); } fail: return (int) et; }; qpol_bool_t *get_boolean(qpol_policy_t *p) { uint32_t et; qpol_bool_t *b = NULL; qpol_cond_expr_node_get_expr_type(p, self, &et); if (et != QPOL_COND_EXPR_BOOL) { SWIG_exception(SWIG_TypeError, "Node does not contain a boolean"); } else if (qpol_cond_expr_node_get_bool(p, self, &b)) { SWIG_exception(SWIG_ValueError, "Could not get boolean for node"); } fail: return b; }; }; %inline %{ qpol_cond_expr_node_t *qpol_cond_expr_node_from_void(void *x) { return (qpol_cond_expr_node_t*)x; } %} /* qpol filename trans */ typedef struct qpol_filename_trans {} qpol_filename_trans_t; %extend qpol_filename_trans { qpol_filename_trans() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_filename_trans_t objects"); fail: return NULL; }; ~qpol_filename_trans() { /* no op */ return; }; %pythoncode %{ def rule_type(self,policy): return QPOL_RULE_TYPE_TRANS %} const qpol_type_t *source_type (qpol_policy_t *p) { const qpol_type_t *t; if (qpol_filename_trans_get_source_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get source for filename transition rule"); } fail: return t; }; const qpol_type_t *target_type (qpol_policy_t *p) { const qpol_type_t *t; if (qpol_filename_trans_get_target_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get target for filename transition rule"); } fail: return t; }; const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_filename_trans_get_object_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class for filename transition rule"); } fail: return cls; }; const qpol_type_t *default_type(qpol_policy_t *p) { const qpol_type_t *t; if (qpol_filename_trans_get_default_type(p, self, &t)) { SWIG_exception(SWIG_ValueError, "Could not get default for filename transition rule"); } fail: return t; }; const char *filename(qpol_policy_t *p) { const char *name; if (qpol_filename_trans_get_filename(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get file for filename transition rule"); } fail: return name; }; }; %inline %{ qpol_filename_trans_t *qpol_filename_trans_from_void(void *x) { return (qpol_filename_trans_t*)x; } %} /* qpol polcap */ typedef struct qpol_polcap {} qpol_polcap_t; %extend qpol_polcap { qpol_polcap() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_polcap_t objects"); fail: return NULL; }; ~qpol_polcap() { /* no op */ return; }; const char *name(qpol_policy_t *p) { const char *name; if (qpol_polcap_get_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get polcap name rule"); } fail: return name; }; }; %inline %{ qpol_polcap_t *qpol_polcap_from_void(void *x) { return (qpol_polcap_t*)x; } %} /* qpol typebounds */ typedef struct qpol_typebounds {} qpol_typebounds_t; %extend qpol_typebounds { qpol_typebounds() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_typebounds_t objects"); fail: return NULL; }; ~qpol_typebounds() { /* no op */ return; }; const char *parent_name(qpol_policy_t *p) { const char *name; if (qpol_typebounds_get_parent_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get parent name"); } fail: return name; }; const char *child_name(qpol_policy_t *p) { const char *name; if (qpol_typebounds_get_child_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get child name"); } fail: return name; }; }; %inline %{ qpol_typebounds_t *qpol_typebounds_from_void(void *x) { return (qpol_typebounds_t*)x; } %} /* qpol rolebounds */ typedef struct qpol_rolebounds {} qpol_rolebounds_t; %extend qpol_rolebounds { qpol_rolebounds() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_rolebounds_t objects"); fail: return NULL; }; ~qpol_rolebounds() { /* no op */ return; }; const char *parent_name(qpol_policy_t *p) { const char *name; if (qpol_rolebounds_get_parent_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get parent name"); } fail: return name; }; const char *child_name(qpol_policy_t *p) { const char *name; if (qpol_rolebounds_get_child_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get child name"); } fail: return name; }; }; %inline %{ qpol_rolebounds_t *qpol_rolebounds_from_void(void *x) { return (qpol_rolebounds_t*)x; } %} /* qpol userbounds */ typedef struct qpol_userbounds {} qpol_userbounds_t; %extend qpol_userbounds { qpol_userbounds() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_userbounds_t objects"); fail: return NULL; }; ~qpol_userbounds() { /* no op */ return; }; const char *parent_name(qpol_policy_t *p) { const char *name; if (qpol_userbounds_get_parent_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get parent name"); } fail: return name; }; const char *child_name(qpol_policy_t *p) { const char *name; if (qpol_userbounds_get_child_name(p, self, &name)) { SWIG_exception(SWIG_ValueError, "Could not get child name"); } fail: return name; }; }; %inline %{ qpol_userbounds_t *qpol_userbounds_from_void(void *x) { return (qpol_userbounds_t*)x; } %} /* qpol default_object */ typedef struct qpol_default_object {} qpol_default_object_t; %extend qpol_default_object { qpol_default_object() { SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_default_object_t objects"); fail: return NULL; }; ~qpol_default_object() { /* no op */ return; }; %newobject object_class(); const qpol_class_t *object_class(qpol_policy_t *p) { const qpol_class_t *cls; if (qpol_default_object_get_class(p, self, &cls)) { SWIG_exception(SWIG_ValueError, "Could not get class"); } fail: return cls; }; const char *user_default(qpol_policy_t *p) { const char *value; if (qpol_default_object_get_user_default(p, self, &value)) { SWIG_exception(SWIG_ValueError, "Could not get user default"); } fail: return value; }; const char *role_default(qpol_policy_t *p) { const char *value; if (qpol_default_object_get_role_default(p, self, &value)) { SWIG_exception(SWIG_ValueError, "Could not get role default"); } fail: return value; }; const char *type_default(qpol_policy_t *p) { const char *value; if (qpol_default_object_get_type_default(p, self, &value)) { SWIG_exception(SWIG_ValueError, "Could not get type default"); } fail: return value; }; const char *range_default(qpol_policy_t *p) { const char *value; if (qpol_default_object_get_range_default(p, self, &value)) { SWIG_exception(SWIG_ValueError, "Could not get range defaults"); } fail: return value; }; }; %inline %{ qpol_default_object_t *qpol_default_object_from_void(void *x) { return (qpol_default_object_t*)x; } %} /* qpol iomemcon */ typedef struct qpol_iomemcon {} qpol_iomemcon_t; %extend qpol_iomemcon { qpol_iomemcon(qpol_policy_t *p, uint64_t low, uint64_t high) { const qpol_iomemcon_t *qp; if (qpol_policy_get_iomemcon_by_addr(p, low, high, &qp)) { SWIG_exception(SWIG_RuntimeError, "iomemcon statement does not exist"); } fail: return (qpol_iomemcon_t*)qp; }; ~qpol_iomemcon() { /* no op */ return; }; uint64_t low_addr(qpol_policy_t *p) { uint64_t addr = 0; if(qpol_iomemcon_get_low_addr(p, self, &addr)) { SWIG_exception(SWIG_RuntimeError, "Could not get low addr for iomemcon statement"); } fail: return addr; }; uint64_t high_addr(qpol_policy_t *p) { uint64_t addr = 0; if(qpol_iomemcon_get_high_addr(p, self, &addr)) { SWIG_exception(SWIG_RuntimeError, "Could not get high addr for iomemcon statement"); } fail: return addr; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_iomemcon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for iomemcon statement"); } fail: return ctx; }; } %inline %{ qpol_iomemcon_t *qpol_iomemcon_from_void(void *x) { return (qpol_iomemcon_t*)x; } %} /* qpol ioportcon */ typedef struct qpol_ioportcon {} qpol_ioportcon_t; %extend qpol_ioportcon { qpol_ioportcon(qpol_policy_t *p, uint32_t low, uint32_t high) { const qpol_ioportcon_t *qp; if (qpol_policy_get_ioportcon_by_port(p, low, high, &qp)) { SWIG_exception(SWIG_RuntimeError, "ioportcon statement does not exist"); } fail: return (qpol_ioportcon_t*)qp; }; ~qpol_ioportcon() { /* no op */ return; }; uint32_t low_port(qpol_policy_t *p) { uint32_t port = 0; if(qpol_ioportcon_get_low_port(p, self, &port)) { SWIG_exception(SWIG_RuntimeError, "Could not get low port for ioportcon statement"); } fail: return port; }; uint32_t high_port(qpol_policy_t *p) { uint32_t port = 0; if(qpol_ioportcon_get_high_port(p, self, &port)) { SWIG_exception(SWIG_RuntimeError, "Could not get high port for ioportcon statement"); } fail: return port; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_ioportcon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for ioportcon statement"); } fail: return ctx; }; } %inline %{ qpol_ioportcon_t *qpol_ioportcon_from_void(void *x) { return (qpol_ioportcon_t*)x; } %} /* qpol pcidevicecon */ typedef struct qpol_pcidevicecon {} qpol_pcidevicecon_t; %extend qpol_pcidevicecon { qpol_pcidevicecon() { SWIG_exception(SWIG_RuntimeError, "pcidevicecon statement does not exist"); fail: return NULL; }; ~qpol_pcidevicecon() { return; }; uint32_t device(qpol_policy_t *p) { uint32_t device = 0; if(qpol_pcidevicecon_get_device(p, self, &device)) { SWIG_exception(SWIG_RuntimeError, "Could not get device for pcidevicecon statement"); } fail: return device; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_pcidevicecon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for pcidevicecon statement"); } fail: return ctx; }; } %inline %{ qpol_pcidevicecon_t *qpol_pcidevicecon_from_void(void *x) { return (qpol_pcidevicecon_t*)x; } %} /* qpol pirqcon */ typedef struct qpol_pirqcon {} qpol_pirqcon_t; %extend qpol_pirqcon { qpol_pirqcon() { SWIG_exception(SWIG_RuntimeError, "pirqcon statement does not exist"); fail: return NULL; }; ~qpol_pirqcon() { return; }; uint32_t irq(qpol_policy_t *p) { uint16_t irq = 0; if(qpol_pirqcon_get_irq(p, self, &irq)) { SWIG_exception(SWIG_RuntimeError, "Could not get irq for pirqcon statement"); } fail: return irq; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_pirqcon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for pirqcon statement"); } fail: return ctx; }; } %inline %{ qpol_pirqcon_t *qpol_pirqcon_from_void(void *x) { return (qpol_pirqcon_t*)x; } %} /* qpol devicetreecon */ typedef struct qpol_devicetreecon {} qpol_devicetreecon_t; %extend qpol_devicetreecon { qpol_devicetreecon() { SWIG_exception(SWIG_RuntimeError, "devicetreecon statement does not exist"); fail: return NULL; }; char *path(qpol_policy_t *p) { char *path = NULL; if(qpol_devicetreecon_get_path(p, self, &path)) { SWIG_exception(SWIG_RuntimeError, "Could not get path for devicetreecon statement"); } fail: return path; }; const qpol_context_t *context(qpol_policy_t *p) { const qpol_context_t *ctx; if (qpol_devicetreecon_get_context(p, self, &ctx)) { SWIG_exception(SWIG_ValueError, "Could not get context for devicetreecon statement"); } fail: return ctx; }; } %inline %{ qpol_devicetreecon_t *qpol_devicetreecon_from_void(void *x) { return (qpol_devicetreecon_t*)x; } %} setools-4.1.1/setools/policyrep/rbacrule.py000066400000000000000000000115051314142262400210550ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import itertools from . import exception from . import qpol from . import rule from . import role from . import typeattr from .util import PolicyEnum def rbac_rule_factory(policy, name): """Factory function for creating RBAC rule objects.""" if isinstance(name, qpol.qpol_role_allow_t): return RoleAllow(policy, name) elif isinstance(name, qpol.qpol_role_trans_t): return RoleTransition(policy, name) else: raise TypeError("RBAC rules cannot be looked up.") def expanded_rbac_rule_factory(original, source, target): """ Factory function for creating expanded RBAC rules. original The RBAC rule the expanded rule originates from. source The source type of the expanded rule. target The target type of the expanded rule. """ if isinstance(original, (ExpandedRoleAllow, ExpandedRoleTransition)): return original elif isinstance(original, RoleAllow): rule = ExpandedRoleAllow(original.policy, original.qpol_symbol) elif isinstance(original, RoleTransition): rule = ExpandedRoleTransition(original.policy, original.qpol_symbol) else: raise TypeError("The original rule must be an RBAC rule class.") rule.source = source rule.target = target rule.origin = original return rule def validate_ruletype(t): """Validate RBAC rule types.""" try: return RBACRuletype.lookup(t) except KeyError: raise exception.InvalidRBACRuleType("{0} is not a valid RBAC rule type.".format(t)) class RBACRuletype(PolicyEnum): """An enumeration of RBAC rule types.""" allow = 1 role_transition = 2 class RoleAllow(rule.PolicyRule): """A role allow rule.""" __slots__ = () def __str__(self): return "{0.ruletype} {0.source} {0.target};".format(self) def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}".format(self)) ruletype = RBACRuletype.allow @property def source(self): """The rule's source role.""" return role.role_factory(self.policy, self.qpol_symbol.source_role(self.policy)) @property def target(self): """The rule's target role.""" return role.role_factory(self.policy, self.qpol_symbol.target_role(self.policy)) @property def tclass(self): """The rule's object class.""" raise exception.RuleUseError("Role allow rules do not have an object class.") @property def default(self): """The rule's default role.""" raise exception.RuleUseError("Role allow rules do not have a default role.") def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" for s, t in itertools.product(self.source.expand(), self.target.expand()): yield expanded_rbac_rule_factory(self, s, t) class RoleTransition(rule.PolicyRule): """A role_transition rule.""" __slots__ = () def __str__(self): return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default};".format(self) ruletype = RBACRuletype.role_transition @property def source(self): """The rule's source role.""" return role.role_factory(self.policy, self.qpol_symbol.source_role(self.policy)) @property def target(self): """The rule's target type/attribute.""" return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) @property def default(self): """The rule's default role.""" return role.role_factory(self.policy, self.qpol_symbol.default_role(self.policy)) def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" for s, t in itertools.product(self.source.expand(), self.target.expand()): yield expanded_rbac_rule_factory(self, s, t) class ExpandedRoleAllow(RoleAllow): """An expanded role allow rule.""" __slots__ = ("source", "target", "origin") class ExpandedRoleTransition(RoleTransition): """An expanded role_transition rule.""" __slots__ = ("source", "target", "origin") setools-4.1.1/setools/policyrep/role.py000066400000000000000000000043031314142262400202150ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import qpol from . import symbol from . import typeattr def role_factory(qpol_policy, name): """Factory function for creating Role objects.""" if isinstance(name, Role): assert name.policy == qpol_policy return name elif isinstance(name, qpol.qpol_role_t): return Role(qpol_policy, name) try: return Role(qpol_policy, qpol.qpol_role_t(qpol_policy, str(name))) except ValueError: raise exception.InvalidRole("{0} is not a valid role".format(name)) class BaseRole(symbol.PolicySymbol): """Role/role attribute base class.""" def expand(self): raise NotImplementedError def types(self): raise NotImplementedError class Role(BaseRole): """A role.""" def expand(self): """Generator that expands this into its member roles.""" yield self def types(self): """Generator which yields the role's set of types.""" for type_ in self.qpol_symbol.type_iter(self.policy): yield typeattr.type_or_attr_factory(self.policy, type_) def statement(self): types = list(str(t) for t in self.types()) stmt = "role {0}".format(self) if types: if (len(types) > 1): stmt += " types {{ {0} }}".format(' '.join(types)) else: stmt += " types {0}".format(types[0]) stmt += ";" return stmt class RoleAttribute(BaseRole): """A role attribute.""" pass setools-4.1.1/setools/policyrep/rule.py000066400000000000000000000052361314142262400202310ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import symbol from . import objclass class PolicyRule(symbol.PolicySymbol): """This is base class for policy rules.""" __slots__ = () extended = False def __str__(self): raise NotImplementedError def __hash__(self): try: cond = self.conditional cond_block = self.conditional_block except exception.RuleNotConditional: cond = None cond_block = None return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{1}|{2}".format( self, cond, cond_block)) @property def ruletype(self): """The rule type for the rule.""" raise NotImplementedError @property def source(self): """ The source for the rule. This should be overridden by subclasses. """ raise NotImplementedError @property def target(self): """ The target for the rule. This should be overridden by subclasses. """ raise NotImplementedError @property def tclass(self): """The object class for the rule.""" return objclass.class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) @property def default(self): """ The default for the rule. This should be overridden by subclasses. """ raise NotImplementedError @property def conditional(self): """The conditional expression for this rule.""" # Most rules cannot be conditional. raise exception.RuleNotConditional @property def conditional_block(self): """The conditional block of the rule (T/F)""" # Most rules cannot be conditional. raise exception.RuleNotConditional def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" raise NotImplementedError def statement(self): return str(self) setools-4.1.1/setools/policyrep/selinuxpolicy.py000066400000000000000000000552611314142262400221740ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=too-many-public-methods import logging import warnings from itertools import chain from errno import ENOENT try: import selinux except ImportError: pass from . import qpol # The libqpol SWIG class is not quite natural for # Python the policy is repeatedly referenced in the # function calls, which makes sense for C code # but not for python code, so each object keeps # a reference to the policy for internal use. # This also makes sense since an object would only # be valid for the policy it comes from. # Exceptions from . import exception # Components from . import boolcond from . import bounds from . import default from . import mls from . import objclass from . import polcap from . import role from . import typeattr from . import user # Rules from . import mlsrule from . import rbacrule from . import terule # Constraints from . import constraint # In-policy Labeling from . import fscontext from . import initsid from . import netcontext # Xen from . import xencontext from .util import PolicyEnum class PolicyTarget(PolicyEnum): """Enumeration of policy targets.""" selinux = qpol.QPOL_TARGET_SELINUX xen = qpol.QPOL_TARGET_XEN class HandleUnknown(PolicyEnum): """Enumeration of handle unknown settings.""" deny = qpol.QPOL_DENY_UNKNOWN allow = qpol.QPOL_ALLOW_UNKNOWN reject = qpol.QPOL_REJECT_UNKNOWN class SELinuxPolicy(object): """The complete SELinux policy.""" def __init__(self, policyfile=None): """ Parameter: policyfile Path to a policy to open. """ self.log = logging.getLogger(__name__) self.policy = None self.filename = None if policyfile: self._load_policy(policyfile) else: try: self._load_running_policy() except NameError: raise RuntimeError("Loading the running policy requires libselinux Python bindings") def __repr__(self): return "".format(self.filename) def __str__(self): return self.filename def __deepcopy__(self, memo): # shallow copy as all of the members are immutable newobj = SELinuxPolicy.__new__(SELinuxPolicy) newobj.policy = self.policy newobj.filename = self.filename memo[id(self)] = newobj return newobj # # Policy loading functions # def _load_policy(self, filename): """Load the specified policy.""" self.log.info("Opening SELinux policy \"{0}\"".format(filename)) try: self.policy = qpol.qpol_policy_factory(str(filename)) except SyntaxError as err: raise exception.InvalidPolicy("Error opening policy file \"{0}\": {1}". format(filename, err)) self.log.info("Successfully opened SELinux policy \"{0}\"".format(filename)) self.filename = filename @staticmethod def _potential_policies(): """Generate a list of potential policies to use.""" # try libselinux for current policy if selinux.selinuxfs_exists(): yield selinux.selinux_current_policy_path() # otherwise look through the supported policy versions base_policy_path = selinux.selinux_binary_policy_path() for version in range(qpol.QPOL_POLICY_MAX_VERSION, qpol.QPOL_POLICY_MIN_VERSION-1, -1): yield "{0}.{1}".format(base_policy_path, version) def _load_running_policy(self): """Try to load the current running policy.""" self.log.info("Attempting to locate current running policy.") for filename in self._potential_policies(): try: self._load_policy(filename) except OSError as err: if err.errno != ENOENT: raise else: break else: raise RuntimeError("Unable to locate an SELinux policy to load.") # # Policy properties # @property def handle_unknown(self): """The handle unknown permissions setting (allow,deny,reject)""" return HandleUnknown(self.policy.handle_unknown()) @property def mls(self): """(T/F) The policy has MLS enabled.""" return mls.enabled(self.policy) @property def version(self): """The policy database version (e.g. v29)""" return self.policy.version() @property def target_platform(self): """The policy platform (selinux or xen)""" return PolicyTarget(self.policy.target_platform()) # # Policy statistics # @property def allow_count(self): """The number of (type) allow rules.""" return self.policy.avrule_allow_count() @property def allowxperm_count(self): """The number of allowxperm rules.""" return self.policy.avrule_allowx_count() @property def auditallow_count(self): """The number of auditallow rules.""" return self.policy.avrule_auditallow_count() @property def auditallowxperm_count(self): """The number of auditallowxperm rules.""" return self.policy.avrule_auditallowx_count() @property def boolean_count(self): """The number of Booleans.""" return self.policy.bool_count() @property def category_count(self): """The number of categories.""" return sum(1 for _ in self.categories()) @property def class_count(self): """The number of object classes.""" return self.policy.class_count() @property def common_count(self): """The number of common permission sets.""" return self.policy.common_count() @property def conditional_count(self): """The number of conditionals.""" return self.policy.cond_count() @property def constraint_count(self): """The number of standard constraints.""" return sum(1 for c in self.constraints() if c.ruletype == constraint.ConstraintRuletype.constrain) @property def default_count(self): """The number of default_* rules.""" return sum(1 for d in self.defaults()) @property def devicetreecon_count(self): """The number of Xen devicetreecon statements.""" return self.policy.devicetreecon_count() @property def dontaudit_count(self): """The number of dontaudit rules.""" return self.policy.avrule_dontaudit_count() @property def dontauditxperm_count(self): """The number of dontauditxperm rules.""" return self.policy.avrule_dontauditx_count() @property def fs_use_count(self): """fs_use_* statements.""" return self.policy.fs_use_count() @property def genfscon_count(self): """The number of genfscon statements.""" return self.policy.genfscon_count() @property def initialsids_count(self): """The number of initial sid statements.""" return self.policy.isid_count() @property def iomemcon_count(self): """The number of Xen iomemcon statements.""" return self.policy.iomemcon_count() @property def ioportcon_count(self): """The number of Xen ioportcon statements.""" return self.policy.ioportcon_count() @property def level_count(self): """The number of levels.""" return sum(1 for _ in self.levels()) @property def mlsconstraint_count(self): """The number of MLS constraints.""" return sum(1 for c in self.constraints() if c.ruletype == constraint.ConstraintRuletype.mlsconstrain) @property def mlsvalidatetrans_count(self): """The number of MLS validatetrans.""" return sum(1 for v in self.constraints() if v.ruletype == constraint.ConstraintRuletype.mlsvalidatetrans) @property def netifcon_count(self): """The number of netifcon statements.""" return self.policy.netifcon_count() @property def neverallow_count(self): """The number of neverallow rules.""" return self.policy.avrule_neverallow_count() @property def neverallowxperm_count(self): """The number of neverallowxperm rules.""" return self.policy.avrule_neverallowx_count() @property def nodecon_count(self): """The number of nodecon statements.""" return self.policy.nodecon_count() @property def pcidevicecon_count(self): """The number of Xen pcidevicecon statements.""" return self.policy.pcidevicecon_count() @property def permission_count(self): """The number of permissions.""" return sum(len(c.perms) for c in chain(self.commons(), self.classes())) @property def permissives_count(self): """The number of permissive types.""" return self.policy.permissive_count() @property def pirqcon_count(self): """The number of Xen pirqcon statements.""" return self.policy.pirqcon_count() @property def polcap_count(self): """The number of policy capabilities.""" return self.policy.polcap_count() @property def portcon_count(self): """The number of portcon statements.""" return self.policy.portcon_count() @property def range_transition_count(self): """The number of range_transition rules.""" return self.policy.range_trans_count() @property def role_count(self): """The number of roles.""" return self.policy.role_count() @property def role_allow_count(self): """The number of (role) allow rules.""" return self.policy.role_allow_count() @property def role_transition_count(self): """The number of role_transition rules.""" return self.policy.role_trans_count() @property def type_attribute_count(self): """The number of (type) attributes.""" return sum(1 for _ in self.typeattributes()) @property def type_count(self): """The number of types.""" return sum(1 for _ in self.types()) @property def type_change_count(self): """The number of type_change rules.""" return self.policy.terule_change_count() @property def type_member_count(self): """The number of type_member rules.""" return self.policy.terule_member_count() @property def type_transition_count(self): """The number of type_transition rules.""" return self.policy.terule_trans_count() + self.policy.filename_trans_count() @property def typebounds_count(self): """The number of typebounds rules.""" return sum(1 for b in self.bounds() if b.ruletype == bounds.BoundsRuletype.typebounds) @property def user_count(self): """The number of users.""" return self.policy.user_count() @property def validatetrans_count(self): """The number of validatetrans.""" return sum(1 for v in self.constraints() if v.ruletype == constraint.ConstraintRuletype.validatetrans) # # Policy components lookup functions # def lookup_boolean(self, name): """Look up a Boolean.""" return boolcond.boolean_factory(self.policy, name) def lookup_class(self, name): """Look up an object class.""" return objclass.class_factory(self.policy, name) def lookup_common(self, name): """Look up a common permission set.""" return objclass.common_factory(self.policy, name) def lookup_initialsid(self, name): """Look up an initial sid.""" return initsid.initialsid_factory(self.policy, name) def lookup_level(self, level): """Look up a MLS level.""" return mls.level_factory(self.policy, level) def lookup_sensitivity(self, name): """Look up a MLS sensitivity by name.""" return mls.sensitivity_factory(self.policy, name) def lookup_range(self, range_): """Look up a MLS range.""" return mls.range_factory(self.policy, range_) def lookup_role(self, name): """Look up a role by name.""" return role.role_factory(self.policy, name) def lookup_type(self, name): """Look up a type by name.""" return typeattr.type_factory(self.policy, name, deref=True) def lookup_type_or_attr(self, name): """Look up a type or type attribute by name.""" return typeattr.type_or_attr_factory(self.policy, name, deref=True) def lookup_typeattr(self, name): """Look up a type attribute by name.""" return typeattr.attribute_factory(self.policy, name) def lookup_user(self, name): """Look up a user by name.""" return user.user_factory(self.policy, name) # # Policy components generators # def bools(self): """Generator which yields all Booleans.""" for bool_ in self.policy.bool_iter(): yield boolcond.boolean_factory(self.policy, bool_) def bounds(self): """Generator which yields all *bounds statements (typebounds, etc.)""" for bound in self.policy.typebounds_iter(): yield bounds.bounds_factory(self.policy, bound) def categories(self): """Generator which yields all MLS categories.""" for cat in self.policy.cat_iter(): try: yield mls.category_factory(self.policy, cat) except TypeError: # libqpol unfortunately iterates over aliases too pass def classes(self): """Generator which yields all object classes.""" for class_ in self.policy.class_iter(): yield objclass.class_factory(self.policy, class_) def commons(self): """Generator which yields all commons.""" for common in self.policy.common_iter(): yield objclass.common_factory(self.policy, common) def defaults(self): """Generator which yields all default_* statements.""" for default_ in self.policy.default_iter(): try: for default_obj in default.default_factory(self.policy, default_): yield default_obj except exception.NoDefaults: # qpol iterates over all classes. Handle case # where a class has no default_* settings. pass def levels(self): """Generator which yields all level declarations.""" for level in self.policy.level_iter(): try: yield mls.level_decl_factory(self.policy, level) except TypeError: # libqpol unfortunately iterates over levels and sens aliases pass def polcaps(self): """Generator which yields all policy capabilities.""" for cap in self.policy.polcap_iter(): yield polcap.polcap_factory(self.policy, cap) def roles(self): """Generator which yields all roles.""" for role_ in self.policy.role_iter(): yield role.role_factory(self.policy, role_) def sensitivities(self): """Generator which yields all sensitivities.""" # see mls.py for more info on why level_iter is used here. for sens in self.policy.level_iter(): try: yield mls.sensitivity_factory(self.policy, sens) except TypeError: # libqpol unfortunately iterates over sens and aliases pass def types(self): """Generator which yields all types.""" for type_ in self.policy.type_iter(): try: yield typeattr.type_factory(self.policy, type_) except TypeError: # libqpol unfortunately iterates over attributes and aliases pass def typeattributes(self): """Generator which yields all (type) attributes.""" for type_ in self.policy.type_iter(): try: yield typeattr.attribute_factory(self.policy, type_) except TypeError: # libqpol unfortunately iterates over attributes and aliases pass def users(self): """Generator which yields all users.""" for user_ in self.policy.user_iter(): yield user.user_factory(self.policy, user_) # # Policy rules generators # def mlsrules(self): """Generator which yields all MLS rules.""" for rule in self.policy.range_trans_iter(): yield mlsrule.mls_rule_factory(self.policy, rule) def rbacrules(self): """Generator which yields all RBAC rules.""" for rule in chain(self.policy.role_allow_iter(), self.policy.role_trans_iter()): yield rbacrule.rbac_rule_factory(self.policy, rule) def terules(self): """Generator which yields all type enforcement rules.""" for rule in chain(self.policy.avrule_iter(), self.policy.avrulex_iter(), self.policy.terule_iter(), self.policy.filename_trans_iter()): yield terule.te_rule_factory(self.policy, rule) # # Policy rule type validators # @staticmethod def validate_bounds_ruletype(types): """Validate constraint types.""" warnings.warn("Bounds ruletypes have changed to an enumeration.", DeprecationWarning) return bounds.validate_ruletype(types) @staticmethod def validate_constraint_ruletype(types): """Validate constraint types.""" warnings.warn("Constraint ruletypes have changed to an enumeration.", DeprecationWarning) return constraint.validate_ruletype(types) @staticmethod def validate_default_ruletype(types): """Validate default_* types.""" warnings.warn("Default ruletypes have changed to an enumeration.", DeprecationWarning) return default.validate_ruletype(types) @staticmethod def validate_default_value(value): """Validate default_* values.""" warnings.warn("Default values have changed to an enumeration.", DeprecationWarning) return default.validate_default_value(value) @staticmethod def validate_default_range(value): """Validate default_range range.""" warnings.warn("Default range values have changed to an enumeration.", DeprecationWarning) return default.validate_default_range(value) @staticmethod def validate_fs_use_ruletype(types): """Validate fs_use_* rule types.""" return fscontext.validate_ruletype(types) @staticmethod def validate_mls_ruletype(types): """Validate MLS rule types.""" warnings.warn("MLS ruletypes have changed to an enumeration.", DeprecationWarning) return mlsrule.validate_ruletype(types) @staticmethod def validate_rbac_ruletype(types): """Validate RBAC rule types.""" warnings.warn("RBAC ruletypes have changed to an enumeration.", DeprecationWarning) return rbacrule.validate_ruletype(types) @staticmethod def validate_te_ruletype(types): """Validate type enforcement rule types.""" warnings.warn("TE ruletypes have changed to an enumeration.", DeprecationWarning) return terule.validate_ruletype(types) # # Constraints generators # def constraints(self): """Generator which yields all constraints (regular and MLS).""" for constraint_ in chain(self.policy.constraint_iter(), self.policy.validatetrans_iter()): yield constraint.constraint_factory(self.policy, constraint_) # # In-policy Labeling statement generators # def fs_uses(self): """Generator which yields all fs_use_* statements.""" for fs_use in self.policy.fs_use_iter(): yield fscontext.fs_use_factory(self.policy, fs_use) def genfscons(self): """Generator which yields all genfscon statements.""" for fscon in self.policy.genfscon_iter(): yield fscontext.genfscon_factory(self.policy, fscon) def initialsids(self): """Generator which yields all initial SID statements.""" for sid in self.policy.isid_iter(): yield initsid.initialsid_factory(self.policy, sid) def netifcons(self): """Generator which yields all netifcon statements.""" for ifcon in self.policy.netifcon_iter(): yield netcontext.netifcon_factory(self.policy, ifcon) def nodecons(self): """Generator which yields all nodecon statements.""" for node in self.policy.nodecon_iter(): yield netcontext.nodecon_factory(self.policy, node) def portcons(self): """Generator which yields all portcon statements.""" for port in self.policy.portcon_iter(): yield netcontext.portcon_factory(self.policy, port) # # Xen labeling statements # def iomemcons(self): """Generator which yields all iomemcon statements.""" for mem_addr in self.policy.iomemcon_iter(): yield xencontext.iomemcon_factory(self.policy, mem_addr) def ioportcons(self): """Generator which yields all ioportcon statements.""" for port in self.policy.ioportcon_iter(): yield xencontext.ioportcon_factory(self.policy, port) def pcidevicecons(self): """Generator which yields all pcidevicecon statements.""" for device in self.policy.pcidevicecon_iter(): yield xencontext.pcidevicecon_factory(self.policy, device) def pirqcons(self): """Generator which yields all pirqcon statements.""" for irq in self.policy.pirqcon_iter(): yield xencontext.pirqcon_factory(self.policy, irq) def devicetreecons(self): """Generator which yields all devicetreecon statements.""" for path in self.policy.devicetreecon_iter(): yield xencontext.devicetreecon_factory(self.policy, path) setools-4.1.1/setools/policyrep/symbol.py000066400000000000000000000043321314142262400205630ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # class PolicySymbol(object): """This is a base class for all policy objects.""" __slots__ = ("policy", "qpol_symbol") def __init__(self, policy, qpol_symbol): """ Parameters: policy The low-level policy object. qpol_symbol The low-level policy symbol object. """ assert qpol_symbol self.policy = policy self.qpol_symbol = qpol_symbol def __str__(self): return self.qpol_symbol.name(self.policy) def __hash__(self): return hash(str(self)) def __eq__(self, other): try: return self.qpol_symbol.this == other.qpol_symbol.this except AttributeError: return str(self) == str(other) def __ne__(self, other): return not self == other def __lt__(self, other): """Comparison used by Python sorting functions.""" return str(self) < str(other) def __repr__(self): return "<{0.__class__.__name__}(,\"{0}\")>".format( self, id(self.policy)) def __deepcopy__(self, memo): # shallow copy as all of the members are immutable cls = self.__class__ newobj = cls.__new__(cls) newobj.policy = self.policy newobj.qpol_symbol = self.qpol_symbol memo[id(self)] = newobj return newobj def statement(self): """ A rendering of the policy statement. This should be overridden by subclasses. """ raise NotImplementedError setools-4.1.1/setools/policyrep/terule.py000066400000000000000000000267471314142262400205740ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import itertools from . import exception from . import qpol from . import rule from . import typeattr from . import boolcond from .util import PolicyEnum def te_rule_factory(policy, symbol): """Factory function for creating TE rule objects.""" if isinstance(symbol, qpol.qpol_avrule_t): if symbol.is_extended(policy): return AVRuleXperm(policy, symbol) else: return AVRule(policy, symbol) elif isinstance(symbol, (qpol.qpol_terule_t, qpol.qpol_filename_trans_t)): return TERule(policy, symbol) else: raise TypeError("TE rules cannot be looked-up.") def expanded_te_rule_factory(original, source, target): """ Factory function for creating expanded TE rules. original The TE rule the expanded rule originates from. source The source type of the expanded rule. target The target type of the expanded rule. """ # for AV and AVXperm rules, copy the perms into the # expanded rule, so PolicyDifference can build single expanded # rules with unioned permission sets if isinstance(original, (ExpandedAVRule, ExpandedAVRuleXperm, ExpandedTERule)): return original elif isinstance(original, AVRuleXperm): rule = ExpandedAVRuleXperm(original.policy, original.qpol_symbol) rule.perms = original.perms elif isinstance(original, AVRule): rule = ExpandedAVRule(original.policy, original.qpol_symbol) rule.perms = original.perms elif isinstance(original, TERule): rule = ExpandedTERule(original.policy, original.qpol_symbol) else: raise TypeError("The original rule must be a TE rule class.") rule.source = source rule.target = target rule.origin = original return rule def validate_ruletype(t): """Validate TE Rule types.""" try: return TERuletype.lookup(t) except KeyError: raise exception.InvalidTERuleType("{0} is not a valid TE rule type.".format(t)) class TERuletype(PolicyEnum): """Enumeration of types of TE rules.""" allow = qpol.QPOL_RULE_ALLOW neverallow = qpol.QPOL_RULE_NEVERALLOW auditallow = qpol.QPOL_RULE_AUDITALLOW dontaudit = qpol.QPOL_RULE_DONTAUDIT allowxperm = qpol.QPOL_RULE_XPERMS_ALLOW neverallowxperm = qpol.QPOL_RULE_XPERMS_NEVERALLOW auditallowxperm = qpol.QPOL_RULE_XPERMS_AUDITALLOW dontauditxperm = qpol.QPOL_RULE_XPERMS_DONTAUDIT type_transition = qpol.QPOL_RULE_TYPE_TRANS type_change = qpol.QPOL_RULE_TYPE_CHANGE type_member = qpol.QPOL_RULE_TYPE_MEMBER class BaseTERule(rule.PolicyRule): """A type enforcement rule.""" __slots__ = () @property def ruletype(self): """The rule type.""" return TERuletype(self.qpol_symbol.rule_type(self.policy)) @property def source(self): """The rule's source type/attribute.""" return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.source_type(self.policy)) @property def target(self): """The rule's target type/attribute.""" return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) @property def filename(self): raise NotImplementedError @property def conditional(self): """The rule's conditional expression.""" try: return boolcond.condexpr_factory(self.policy, self.qpol_symbol.cond(self.policy)) except AttributeError: raise exception.RuleNotConditional @property def conditional_block(self): """ The conditional block of the rule (T/F) For example, if the policy looks like this: if ( the_conditional_expression ) { If the rule is here, this property is True } else { If the rule is here, this property is False } """ try: return bool(self.qpol_symbol.which_list(self.policy)) except AttributeError: raise exception.RuleNotConditional def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" for s, t in itertools.product(self.source.expand(), self.target.expand()): yield expanded_te_rule_factory(self, s, t) class AVRule(BaseTERule): """An access vector type enforcement rule.""" __slots__ = ("_rule_string") def __str__(self): try: return self._rule_string except AttributeError: self._rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} ".format(self) # allow/dontaudit/auditallow/neverallow rules perms = self.perms if len(perms) > 1: self._rule_string += "{{ {0} }};".format(' '.join(sorted(perms))) else: # convert to list since sets cannot be indexed self._rule_string += "{0};".format(list(perms)[0]) try: self._rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) except exception.RuleNotConditional: pass return self._rule_string @property def perms(self): """The rule's permission set.""" return set(self.qpol_symbol.perm_iter(self.policy)) @property def default(self): """The rule's default type.""" raise exception.RuleUseError("{0} rules do not have a default type.".format(self.ruletype)) @property def filename(self): raise exception.RuleUseError("{0} rules do not have file names".format(self.ruletype)) class IoctlSet(set): """ A set with overridden string functions which compresses the output into ioctl ranges instead of individual elements. """ def __format__(self, spec): """ String formating. The standard formatting (no specification) will render the ranges of ioctls, space separated. The , option by itself will render the ranges of ioctls, comma separated Any other combination of formatting options will fall back to set's formatting behavior. """ # generate short permission notation perms = sorted(self) shortlist = [] for _, i in itertools.groupby(perms, key=lambda k, c=itertools.count(): k - next(c)): group = list(i) if len(group) > 1: shortlist.append("{0:#06x}-{1:#06x}".format(group[0], group[-1])) else: shortlist.append("{0:#06x}".format(group[0])) if not spec: return " ".join(shortlist) elif spec == ",": return ", ".join(shortlist) else: return super(IoctlSet, self).__format__(spec) def __str__(self): return "{0}".format(self) def __repr__(self): return "{{ {0:,} }}".format(self) def ranges(self): """ Return the number of ranges in the set. Main use is to determine if brackets need to be used in string output. """ return sum(1 for (_a, _b) in itertools.groupby( sorted(self), key=lambda k, c=itertools.count(): k - next(c))) class AVRuleXperm(AVRule): """An extended permission access vector type enforcement rule.""" __slots__ = ("_rule_string") extended = True def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{0.xperm_type}".format(self)) def __str__(self): try: return self._rule_string except AttributeError: self._rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} ". \ format(self) # generate short permission notation perms = self.perms if perms.ranges() > 1: self._rule_string += "{{ {0} }};".format(perms) else: self._rule_string += "{0};".format(perms) return self._rule_string @property def perms(self): """The rule's extended permission set.""" return IoctlSet(self.qpol_symbol.xperm_iter(self.policy)) @property def xperm_type(self): """The standard permission extended by these permissions (e.g. ioctl).""" return self.qpol_symbol.xperm_type(self.policy) class TERule(BaseTERule): """A type_* type enforcement rule.""" __slots__ = ("_rule_string") def __str__(self): try: return self._rule_string except AttributeError: self._rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default}".format( self) try: self._rule_string += " \"{0}\";".format(self.filename) except (exception.TERuleNoFilename, exception.RuleUseError): # invalid use for type_change/member self._rule_string += ";" try: self._rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) except exception.RuleNotConditional: pass return self._rule_string def __hash__(self): try: cond = self.conditional cond_block = self.conditional_block except exception.RuleNotConditional: cond = None cond_block = None try: filename = self.filename except (exception.TERuleNoFilename, exception.RuleUseError): filename = None return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{1}|{2}|{3}".format( self, filename, cond, cond_block)) @property def perms(self): """The rule's permission set.""" raise exception.RuleUseError( "{0} rules do not have a permission set.".format(self.ruletype)) @property def default(self): """The rule's default type.""" return typeattr.type_factory(self.policy, self.qpol_symbol.default_type(self.policy)) @property def filename(self): """The type_transition rule's file name.""" try: return self.qpol_symbol.filename(self.policy) except AttributeError: if self.ruletype == TERuletype.type_transition: raise exception.TERuleNoFilename else: raise exception.RuleUseError("{0} rules do not have file names". format(self.ruletype)) class ExpandedAVRule(AVRule): """An expanded access vector type enforcement rule.""" __slots__ = ("source", "target", "perms", "origin") class ExpandedAVRuleXperm(AVRuleXperm): """An expanded extended permission access vector type enforcement rule.""" __slots__ = ("source", "target", "perms", "origin") class ExpandedTERule(TERule): """An expanded type_* type enforcement rule.""" __slots__ = ("source", "target", "origin") setools-4.1.1/setools/policyrep/typeattr.py000066400000000000000000000126571314142262400211430ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import qpol from . import symbol def _symbol_lookup(qpol_policy, name): """Look up the low-level qpol policy reference""" if isinstance(name, qpol.qpol_type_t): return name try: return qpol.qpol_type_t(qpol_policy, str(name)) except ValueError: raise exception.InvalidType("{0} is not a valid type/attribute".format(name)) def attribute_factory(qpol_policy, name): """Factory function for creating attribute objects.""" if isinstance(name, TypeAttribute): assert name.policy == qpol_policy return name qpol_symbol = _symbol_lookup(qpol_policy, name) if not qpol_symbol.isattr(qpol_policy): raise TypeError("{0} is a type".format(qpol_symbol.name(qpol_policy))) return TypeAttribute(qpol_policy, qpol_symbol) def type_factory(qpol_policy, name, deref=False): """Factory function for creating type objects.""" if isinstance(name, Type): assert name.policy == qpol_policy return name qpol_symbol = _symbol_lookup(qpol_policy, name) if qpol_symbol.isattr(qpol_policy): raise TypeError("{0} is an attribute".format(qpol_symbol.name(qpol_policy))) elif qpol_symbol.isalias(qpol_policy) and not deref: raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) return Type(qpol_policy, qpol_symbol) def type_or_attr_factory(qpol_policy, name, deref=False): """Factory function for creating type or attribute objects.""" if isinstance(name, (Type, TypeAttribute)): assert name.policy == qpol_policy return name qpol_symbol = _symbol_lookup(qpol_policy, name) if qpol_symbol.isalias(qpol_policy) and not deref: raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) if qpol_symbol.isattr(qpol_policy): return TypeAttribute(qpol_policy, qpol_symbol) else: return Type(qpol_policy, qpol_symbol) class BaseType(symbol.PolicySymbol): """Type/attribute base class.""" @property def ispermissive(self): raise NotImplementedError def expand(self): """Generator that expands this attribute into its member types.""" raise NotImplementedError def attributes(self): """Generator that yields all attributes for this type.""" raise NotImplementedError def aliases(self): """Generator that yields all aliases for this type.""" raise NotImplementedError class Type(BaseType): """A type.""" @property def ispermissive(self): """(T/F) the type is permissive.""" return self.qpol_symbol.ispermissive(self.policy) def expand(self): """Generator that expands this into its member types.""" yield self def attributes(self): """Generator that yields all attributes for this type.""" for attr in self.qpol_symbol.attr_iter(self.policy): yield attribute_factory(self.policy, attr) def aliases(self): """Generator that yields all aliases for this type.""" for alias in self.qpol_symbol.alias_iter(self.policy): yield alias def statement(self): attrs = list(self.attributes()) aliases = list(self.aliases()) stmt = "type {0}".format(self) if aliases: if len(aliases) > 1: stmt += " alias {{ {0} }}".format(' '.join(aliases)) else: stmt += " alias {0}".format(aliases[0]) for attr in attrs: stmt += ", {0}".format(attr) stmt += ";" return stmt class TypeAttribute(BaseType): """An attribute.""" def __contains__(self, other): for type_ in self.expand(): if other == type_: return True return False def expand(self): """Generator that expands this attribute into its member types.""" for type_ in self.qpol_symbol.type_iter(self.policy): yield type_factory(self.policy, type_) def attributes(self): """Generator that yields all attributes for this type.""" raise exception.SymbolUseError("{0} is an attribute, thus does not have attributes.". format(self)) def aliases(self): """Generator that yields all aliases for this type.""" raise exception.SymbolUseError("{0} is an attribute, thus does not have aliases.". format(self)) @property def ispermissive(self): """(T/F) the type is permissive.""" raise exception.SymbolUseError("{0} is an attribute, thus cannot be permissive.". format(self)) def statement(self): return "attribute {0};".format(self) setools-4.1.1/setools/policyrep/user.py000066400000000000000000000052001314142262400202270ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import exception from . import qpol from . import role from . import mls from . import symbol def user_factory(qpol_policy, name): """Factory function for creating User objects.""" if isinstance(name, User): assert name.policy == qpol_policy return name elif isinstance(name, qpol.qpol_user_t): return User(qpol_policy, name) try: return User(qpol_policy, qpol.qpol_user_t(qpol_policy, str(name))) except ValueError: raise exception.InvalidUser("{0} is not a valid user".format(name)) class User(symbol.PolicySymbol): """A user.""" @property def roles(self): """The user's set of roles.""" roleset = set() for role_ in self.qpol_symbol.role_iter(self.policy): item = role.role_factory(self.policy, role_) # object_r is implicitly added to all roles by the compiler. # technically it is incorrect to skip it, but policy writers # and analysts don't expect to see it in results, and it # will confuse, especially for role set equality user queries. if item != "object_r": roleset.add(item) return roleset @property def mls_level(self): """The user's default MLS level.""" return mls.level_factory(self.policy, self.qpol_symbol.dfltlevel(self.policy)) @property def mls_range(self): """The user's MLS range.""" return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) def statement(self): roles = list(str(r) for r in self.roles) stmt = "user {0} roles ".format(self) if len(roles) > 1: stmt += "{{ {0} }}".format(' '.join(roles)) else: stmt += roles[0] try: stmt += " level {0.mls_level} range {0.mls_range};".format(self) except exception.MLSDisabled: stmt += ";" return stmt setools-4.1.1/setools/policyrep/util.py000066400000000000000000000035141314142262400202340ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import warnings from enum import Enum class PolicyEnum(Enum): """ Base class for policy enumerations. Standard Enum behavior except for returning the enum name for the default string representation and basic string format. """ def __str__(self): return self.name def __format__(self, spec): if not spec: return self.name else: return super(PolicyEnum, self).__format__(spec) def __eq__(self, other): if isinstance(other, str): warnings.warn("{} has changed to an enumeration. In the future, direct string " "comparisons will be deprecated.".format(self.__class__.__name__), PendingDeprecationWarning) return self.name == other else: return super(PolicyEnum, self).__eq__(other) def __hash__(self): return hash(self.name) @classmethod def lookup(cls, value): """Look up an enumeration by name or value.""" try: return cls(value) except ValueError: return cls[value] setools-4.1.1/setools/policyrep/xencontext.py000066400000000000000000000112701314142262400214540ustar00rootroot00000000000000# Derived from netcontext.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import namedtuple from . import qpol from . import symbol from . import context IomemconRange = namedtuple("IomemconRange", ["low", "high"]) IoportconRange = namedtuple("IoportconRange", ["low", "high"]) def iomemcon_factory(policy, name): """Factory function for creating iomemcon objects.""" if not isinstance(name, qpol.qpol_iomemcon_t): raise NotImplementedError return Iomemcon(policy, name) def ioportcon_factory(policy, name): """Factory function for creating ioportcon objects.""" if not isinstance(name, qpol.qpol_ioportcon_t): raise NotImplementedError return Ioportcon(policy, name) def pirqcon_factory(policy, name): """Factory function for creating pirqcon objects.""" if not isinstance(name, qpol.qpol_pirqcon_t): raise NotImplementedError return Pirqcon(policy, name) def pcidevicecon_factory(policy, name): """Factory function for creating pcidevicecon objects.""" if not isinstance(name, qpol.qpol_pcidevicecon_t): raise NotImplementedError return Pcidevicecon(policy, name) def devicetreecon_factory(policy, name): """Factory function for creating devicetreecon objects.""" if not isinstance(name, qpol.qpol_devicetreecon_t): raise NotImplementedError return Devicetreecon(policy, name) class XenContext(symbol.PolicySymbol): """Base class for in-policy xen labeling rules.""" def __str__(self): raise NotImplementedError @property def context(self): """The context for this statement.""" return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) def statement(self): return str(self) class Iomemcon(XenContext): """A iomemcon statement.""" def __str__(self): low, high = self.addr if low == high: return "iomemcon {0} {1}".format(low, self.context) else: return "iomemcon {0}-{1} {2}".format(low, high, self.context) @property def addr(self): """ The memory range for this iomemcon. Return: Tuple(low, high) low The low memory of the range. high The high memory of the range. """ low = self.qpol_symbol.low_addr(self.policy) high = self.qpol_symbol.high_addr(self.policy) return IomemconRange(low, high) class Ioportcon(XenContext): """A ioportcon statement.""" def __str__(self): low, high = self.ports if low == high: return "ioportcon {0} {1}".format(low, self.context) else: return "ioportcon {0}-{1} {2}".format(low, high, self.context) @property def ports(self): """ The port range for this ioportcon. Return: Tuple(low, high) low The low port of the range. high The high port of the range. """ low = self.qpol_symbol.low_port(self.policy) high = self.qpol_symbol.high_port(self.policy) return IoportconRange(low, high) class Pcidevicecon(XenContext): """A pcidevicecon statement.""" def __str__(self): return "pcidevicecon {0.device} {0.context}".format(self) @property def device(self): """ The device for this pcidevicecon. Return: The PCI device ID. """ return self.qpol_symbol.device(self.policy) class Pirqcon(XenContext): """A pirqcon statement.""" def __str__(self): return "pirqcon {0.irq} {0.context}".format(self) @property def irq(self): """ The irq for this pirqcon. Return: The irq. """ return self.qpol_symbol.irq(self.policy) class Devicetreecon(XenContext): """A devicetreecon statement.""" def __str__(self): return "devicetreecon {0.path} {0.context}".format(self) @property def path(self): """ The path for this devicetreecon. Return: The device path name. """ return self.qpol_symbol.path(self.policy) setools-4.1.1/setools/portconquery.py000066400000000000000000000120561314142262400200240ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from socket import IPPROTO_TCP, IPPROTO_UDP from .mixins import MatchContext from .query import PolicyQuery from .policyrep import PortconRange, PortconProtocol from .util import match_range class PortconQuery(MatchContext, PolicyQuery): """ Port context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: protocol The protocol to match (socket.IPPROTO_TCP for TCP or socket.IPPROTO_UDP for UDP) ports A 2-tuple of the port range to match. (Set both to the same value for a single port) ports_subset If true, the criteria will match if it is a subset of the portcon's range. ports_overlap If true, the criteria will match if it overlaps any of the portcon's range. ports_superset If true, the criteria will match if it is a superset of the portcon's range. ports_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _protocol = None _ports = None ports_subset = False ports_overlap = False ports_superset = False ports_proper = False @property def ports(self): return self._ports @ports.setter def ports(self, value): pending_ports = PortconRange(*value) if all(pending_ports): if pending_ports.low < 1 or pending_ports.high < 1: raise ValueError("Port numbers must be positive: {0.low}-{0.high}". format(pending_ports)) if pending_ports.low > pending_ports.high: raise ValueError( "The low port must be smaller than the high port: {0.low}-{0.high}". format(pending_ports)) self._ports = pending_ports else: self._ports = None @property def protocol(self): return self._protocol @protocol.setter def protocol(self, value): if value: self._protocol = PortconProtocol.lookup(value) else: self._protocol = None def __init__(self, policy, **kwargs): super(PortconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching portcons.""" self.log.info("Generating portcon results from {0.policy}".format(self)) self.log.debug("Ports: {0.ports}, overlap: {0.ports_overlap}, " "subset: {0.ports_subset}, superset: {0.ports_superset}, " "proper: {0.ports_proper}".format(self)) self.log.debug("Protocol: {0.protocol!r}".format(self)) self._match_context_debug(self.log) for portcon in self.policy.portcons(): if self.ports and not match_range( portcon.ports, self.ports, self.ports_subset, self.ports_overlap, self.ports_superset, self.ports_proper): continue if self.protocol and self.protocol != portcon.protocol: continue if not self._match_context(portcon.context): continue yield portcon setools-4.1.1/setools/query.py000066400000000000000000000031671314142262400164220ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging class PolicyQuery(object): """Base class for SELinux policy queries.""" def __init__(self, policy, **kwargs): self.policy = policy # keys are sorted in reverse order so regex settings # are set before the criteria, e.g. name_regex # is set before name. This ensures correct behavior # since the criteria descriptors are sensitve to # regex settings. for name in sorted(kwargs.keys(), reverse=True): attr = getattr(self, name, None) # None is not callable if callable(attr): raise ValueError("Keyword parameter {0} conflicts with a callable.".format(name)) setattr(self, name, kwargs[name]) def results(self): """ Generator which returns the matches for the query. This method should be overridden by subclasses. """ raise NotImplementedError setools-4.1.1/setools/rbacrulequery.py000066400000000000000000000131761314142262400201430ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from . import mixins, query from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .policyrep import RBACRuletype from .policyrep.exception import InvalidType, RuleUseError from .util import match_indirect_regex class RBACRuleQuery(mixins.MatchObjClass, query.PolicyQuery): """ Query the RBAC rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source role/attribute to match. source_indirect If true, members of an attribute will be matched rather than the attribute itself. source_regex If true, regular expression matching will be used on the source role/attribute. Obeys the source_indirect option. target The name of the target role/attribute to match. target_indirect If true, members of an attribute will be matched rather than the attribute itself. target_regex If true, regular expression matching will be used on the target role/attribute. Obeys target_indirect option. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. default The name of the default role to match. default_regex If true, regular expression matching will be used on the default role. """ ruletype = CriteriaSetDescriptor(enum_class=RBACRuletype) source = CriteriaDescriptor("source_regex", "lookup_role") source_regex = False source_indirect = True _target = None target_regex = False target_indirect = True tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex = False default = CriteriaDescriptor("default_regex", "lookup_role") default_regex = False @property def target(self): return self._target @target.setter def target(self, value): if not value: self._target = None elif self.target_regex: self._target = re.compile(value) else: try: self._target = self.policy.lookup_type_or_attr(value) except InvalidType: self._target = self.policy.lookup_role(value) def __init__(self, policy, **kwargs): super(RBACRuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching RBAC rules.""" self.log.info("Generating RBAC rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) for rule in self.policy.rbacrules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source role # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type (role_transition)/role(allow) # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # try: if not self._match_object_class(rule): continue except RuleUseError: continue # # Matching on default role # if self.default: try: # because default role is always a single # role, hard-code indirect to True # so the criteria can be an attribute if not match_indirect_regex( rule.default, self.default, True, self.default_regex): continue except RuleUseError: continue # if we get here, we have matched all available criteria yield rule setools-4.1.1/setools/rolequery.py000066400000000000000000000047541314142262400173070ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaSetDescriptor from .mixins import MatchName from .query import PolicyQuery from .util import match_regex_or_set class RoleQuery(MatchName, PolicyQuery): """ Query SELinux policy roles. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The role name to match. name_regex If true, regular expression matching will be used on the role names. types The type to match. types_equal If true, only roles with type sets that are equal to the criteria will match. Otherwise, any intersection will match. types_regex If true, regular expression matching will be used on the type names instead of set logic. """ types = CriteriaSetDescriptor("types_regex", "lookup_type") types_equal = False types_regex = False def __init__(self, policy, **kwargs): super(RoleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching roles.""" self.log.info("Generating role results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " "eq: {0.types_equal}".format(self)) for r in self.policy.roles(): if not self._match_name(r): continue if self.types and not match_regex_or_set( set(r.types()), self.types, self.types_equal, self.types_regex): continue yield r setools-4.1.1/setools/sensitivityquery.py000066400000000000000000000052361314142262400207340ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from .descriptors import CriteriaDescriptor from .mixins import MatchAlias, MatchName from .query import PolicyQuery from .util import match_level class SensitivityQuery(MatchAlias, MatchName, PolicyQuery): """ Query MLS Sensitivities Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the category to match. name_regex If true, regular expression matching will be used for matching the name. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. sens The criteria to match the sensitivity by dominance. sens_dom If true, the criteria will match if it dominates the sensitivity. sens_domby If true, the criteria will match if it is dominated by the sensitivity. """ sens = CriteriaDescriptor(lookup_function="lookup_sensitivity") sens_dom = False sens_domby = False def __init__(self, policy, **kwargs): super(SensitivityQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching sensitivities.""" self.log.info("Generating sensitivity results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) self.log.debug("Sens: {0.sens!r}, dom: {0.sens_dom}, domby: {0.sens_domby}".format(self)) for s in self.policy.sensitivities(): if not self._match_name(s): continue if not self._match_alias(s): continue if self.sens and not match_level( s, self.sens, self.sens_dom, self.sens_domby, False): continue yield s setools-4.1.1/setools/terulequery.py000066400000000000000000000221571314142262400176430ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from . import mixins, query from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .policyrep import IoctlSet, TERuletype from .policyrep.exception import RuleUseError, RuleNotConditional from .util import match_regex, match_indirect_regex, match_regex_or_set class TERuleQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery): """ Query the Type Enforcement rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source type/attribute to match. source_indirect If true, members of an attribute will be matched rather than the attribute itself. Default is true. source_regex If true, regular expression matching will be used on the source type/attribute. Obeys the source_indirect option. Default is false. target The name of the target type/attribute to match. target_indirect If true, members of an attribute will be matched rather than the attribute itself. Default is true. target_regex If true, regular expression matching will be used on the target type/attribute. Obeys target_indirect option. Default is false. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. Default is false. perms The set of permission(s) to match. perms_equal If true, the permission set of the rule must exactly match the permissions criteria. If false, any set intersection will match. Default is false. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. Default is false. perms_subset If true, the rule matches if the permissions criteria is a subset of the rule's permission set. Default is false. default The name of the default type to match. default_regex If true, regular expression matching will be used on the default type. Default is false. boolean The set of boolean(s) to match. boolean_regex If true, regular expression matching will be used on the booleans. Default is false. boolean_equal If true, the booleans in the conditional expression of the rule must exactly match the criteria. If false, any set intersection will match. Default is false. """ ruletype = CriteriaSetDescriptor(enum_class=TERuletype) source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") source_regex = False source_indirect = True target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") target_regex = False target_indirect = True default = CriteriaDescriptor("default_regex", "lookup_type_or_attr") default_regex = False boolean = CriteriaSetDescriptor("boolean_regex", "lookup_boolean") boolean_regex = False boolean_equal = False _xperms = None xperms_equal = False @property def xperms(self): return self._xperms @xperms.setter def xperms(self, value): if value: pending_xperms = IoctlSet() for low, high in value: if not (0 <= low <= 0xffff): raise ValueError("{0:#07x} is not a valid ioctl.".format(low)) if not (0 <= high <= 0xffff): raise ValueError("{0:#07x} is not a valid ioctl.".format(high)) if high < low: high, low = low, high pending_xperms.update(i for i in range(low, high+1)) self._xperms = pending_xperms else: self._xperms = None def __init__(self, policy, **kwargs): super(TERuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching TE rules.""" self.log.info("Generating TE rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self._match_perms_debug(self.log) self.log.debug("Xperms: {0.xperms!r}, eq: {0.xperms_equal}".format(self)) self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) self.log.debug("Boolean: {0.boolean!r}, eq: {0.boolean_equal}, " "regex: {0.boolean_regex}".format(self)) for rule in self.policy.terules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source type # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # if not self._match_object_class(rule): continue # # Matching on permission set # try: if self.perms and rule.extended: if self.perms_equal and len(self.perms) > 1: # if criteria is more than one standard permission, # extended perm rules can never match if the # permission set equality option is on. continue if rule.xperm_type not in self.perms: continue elif not self._match_perms(rule): continue except RuleUseError: continue # # Matching on extended permissions # try: if self.xperms and not match_regex_or_set( rule.perms, self.xperms, self.xperms_equal, False): continue except RuleUseError: continue # # Matching on default type # if self.default: try: # because default type is always a single # type, hard-code indirect to True # so the criteria can be an attribute if not match_indirect_regex( rule.default, self.default, True, self.default_regex): continue except RuleUseError: continue # # Match on Boolean in conditional expression # if self.boolean: try: if not match_regex_or_set( rule.conditional.booleans, self.boolean, self.boolean_equal, self.boolean_regex): continue except RuleNotConditional: continue # if we get here, we have matched all available criteria yield rule setools-4.1.1/setools/typeattrquery.py000066400000000000000000000051721314142262400202150ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaSetDescriptor from .mixins import MatchName from .query import PolicyQuery from .util import match_regex_or_set class TypeAttributeQuery(MatchName, PolicyQuery): """ Query SELinux policy type attributes. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The type name to match. name_regex If true, regular expression matching will be used on the type names. types The type to match. types_equal If true, only attributes with type sets that are equal to the criteria will match. Otherwise, any intersection will match. types_regex If true, regular expression matching will be used on the type names instead of set logic. """ types = CriteriaSetDescriptor("types_regex", "lookup_type") types_equal = False types_regex = False def __init__(self, policy, **kwargs): super(TypeAttributeQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching types.""" self.log.info("Generating type attribute results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " "eq: {0.types_equal}".format(self)) for attr in self.policy.typeattributes(): if not self._match_name(attr): continue if self.types and not match_regex_or_set( set(attr.expand()), self.types, self.types_equal, self.types_regex): continue yield attr setools-4.1.1/setools/typequery.py000066400000000000000000000066701314142262400173260ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaSetDescriptor from .mixins import MatchAlias, MatchName from .query import PolicyQuery from .util import match_regex_or_set class TypeQuery(MatchAlias, MatchName, PolicyQuery): """ Query SELinux policy types. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The type name to match. name_regex If true, regular expression matching will be used on the type names. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. attrs The attribute to match. attrs_equal If true, only types with attribute sets that are equal to the criteria will match. Otherwise, any intersection will match. attrs_regex If true, regular expression matching will be used on the attribute names instead of set logic. permissive The permissive state to match. If this is None, the state is not matched. """ attrs = CriteriaSetDescriptor("attrs_regex", "lookup_typeattr") attrs_regex = False attrs_equal = False _permissive = None @property def permissive(self): return self._permissive @permissive.setter def permissive(self, value): if value is None: self._permissive = None else: self._permissive = bool(value) def __init__(self, policy, **kwargs): super(TypeQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching types.""" self.log.info("Generating type results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) self.log.debug("Attrs: {0.attrs!r}, regex: {0.attrs_regex}, " "eq: {0.attrs_equal}".format(self)) self.log.debug("Permissive: {0.permissive}".format(self)) for t in self.policy.types(): if not self._match_name(t): continue if not self._match_alias(t): continue if self.attrs and not match_regex_or_set( set(t.attributes()), self.attrs, self.attrs_equal, self.attrs_regex): continue if self.permissive is not None and t.ispermissive != self.permissive: continue yield t setools-4.1.1/setools/userquery.py000066400000000000000000000112671314142262400173210ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchName from .query import PolicyQuery from .util import match_regex_or_set, match_level, match_range class UserQuery(MatchName, PolicyQuery): """ Query SELinux policy users. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The user name to match. name_regex If true, regular expression matching will be used on the user names. roles The attribute to match. roles_equal If true, only types with role sets that are equal to the criteria will match. Otherwise, any intersection will match. roles_regex If true, regular expression matching will be used on the role names instead of set logic. level The criteria to match the user's default level. level_dom If true, the criteria will match if it dominates the user's default level. level_domby If true, the criteria will match if it is dominated by the user's default level. level_incomp If true, the criteria will match if it is incomparable to the user's default level. range_ The criteria to match the user's range. range_subset If true, the criteria will match if it is a subset of the user's range. range_overlap If true, the criteria will match if it overlaps any of the user's range. range_superset If true, the criteria will match if it is a superset of the user's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ level = CriteriaDescriptor(lookup_function="lookup_level") level_dom = False level_domby = False level_incomp = False range_ = CriteriaDescriptor(lookup_function="lookup_range") range_overlap = False range_subset = False range_superset = False range_proper = False roles = CriteriaSetDescriptor("roles_regex", "lookup_role") roles_equal = False roles_regex = False def __init__(self, policy, **kwargs): super(UserQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self): """Generator which yields all matching users.""" self.log.info("Generating user results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Roles: {0.roles!r}, regex: {0.roles_regex}, " "eq: {0.roles_equal}".format(self)) self.log.debug("Level: {0.level!r}, dom: {0.level_dom}, domby: {0.level_domby}, " "incomp: {0.level_incomp}".format(self)) self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) for user in self.policy.users(): if not self._match_name(user): continue if self.roles and not match_regex_or_set( user.roles, self.roles, self.roles_equal, self.roles_regex): continue if self.level and not match_level( user.mls_level, self.level, self.level_dom, self.level_domby, self.level_incomp): continue if self.range_ and not match_range( user.mls_range, self.range_, self.range_subset, self.range_overlap, self.range_superset, self.range_proper): continue yield user setools-4.1.1/setools/util.py000066400000000000000000000125301314142262400162240ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # def match_regex(obj, criteria, regex): """ Match the object with optional regular expression. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. """ if regex: return bool(criteria.search(str(obj))) else: return obj == criteria def match_set(obj, criteria, equal): """ Match the object (a set) with optional set equality. Parameters: obj The object to match. (a set) criteria The criteria to match. (a set) equal If set equality should be used. Otherwise any set intersection will match. """ if equal: return obj == criteria else: return bool(obj.intersection(criteria)) def match_in_set(obj, criteria, regex): """ Match if the criteria is in the list, with optional regular expression matching. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. """ if regex: return [m for m in obj if criteria.search(str(m))] else: return criteria in obj def match_indirect_regex(obj, criteria, indirect, regex): """ Match the object with optional regular expression and indirection. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. indirect If object indirection should be used, e.g. expanding an attribute. """ if indirect: if regex: return [o for o in obj.expand() if criteria.search(str(o))] else: return set(criteria.expand()).intersection(obj.expand()) else: return match_regex(obj, criteria, regex) def match_regex_or_set(obj, criteria, equal, regex): """ Match the object (a set) with either set comparisons (equality or intersection) or by regex matching of the set members. Regular expression matching will override the set equality option. Parameters: obj The object to match. (a set) criteria The criteria to match. equal If set equality should be used. Otherwise any set intersection will match. Ignored if regular expression matching is used. regex If regular expression matching should be used. """ if regex: return [m for m in obj if criteria.search(str(m))] else: return match_set(obj, set(criteria), equal) def match_range(obj, criteria, subset, overlap, superset, proper): """ Match ranges of objects. obj An object with attributes named "low" and "high", representing the range. criteria An object with attributes named "low" and "high", representing the criteria. subset If true, the criteria will match if it is a subset obj's range. overlap If true, the criteria will match if it overlaps any of the obj's range. superset If true, the criteria will match if it is a superset of the obj's range. proper If true, use proper superset/subset operations. No effect if not using set operations. """ if overlap: return ((obj.low <= criteria.low <= obj.high) or ( obj.low <= criteria.high <= obj.high) or ( criteria.low <= obj.low and obj.high <= criteria.high)) elif subset: if proper: return ((obj.low < criteria.low and criteria.high <= obj.high) or ( obj.low <= criteria.low and criteria.high < obj.high)) else: return obj.low <= criteria.low and criteria.high <= obj.high elif superset: if proper: return ((criteria.low < obj.low and obj.high <= criteria.high) or ( criteria.low <= obj.low and obj.high < criteria.high)) else: return (criteria.low <= obj.low and obj.high <= criteria.high) else: return criteria.low == obj.low and obj.high == criteria.high def match_level(obj, criteria, dom, domby, incomp): """ Match the an MLS level. obj The level to match. criteria The criteria to match. (a level) dom If true, the criteria will match if it dominates obj. domby If true, the criteria will match if it is dominated by obj. incomp If true, the criteria will match if it is incomparable to obj. """ if dom: return (criteria >= obj) elif domby: return (criteria <= obj) elif incomp: return (criteria ^ obj) else: return (criteria == obj) setools-4.1.1/setoolsgui/000077500000000000000000000000001314142262400154015ustar00rootroot00000000000000setools-4.1.1/setoolsgui/__init__.py000066400000000000000000000015301314142262400175110ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .apol import ApolMainWindow from . import widget import logging logging.getLogger(__name__).addHandler(logging.NullHandler()) setools-4.1.1/setoolsgui/apol/000077500000000000000000000000001314142262400163345ustar00rootroot00000000000000setools-4.1.1/setoolsgui/apol/__init__.py000066400000000000000000000013731314142262400204510ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .mainwindow import ApolMainWindow setools-4.1.1/setoolsgui/apol/analysistab.py000066400000000000000000000043741314142262400212300ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtWidgets import QDialogButtonBox, QScrollArea from ..widget import SEToolsWidget class AnalysisTab(SEToolsWidget, QScrollArea): """Base class for Apol analysis tabs.""" # A QButtonBox which has an Apply button # for running the analysis. buttonBox = None # The set of tab fields that are in error errors = None # Normal and error palettes to use orig_palette = None error_palette = None # # Tab error state # def set_criteria_error(self, field, error): """Set the specified widget to an error state.""" field.setToolTip("Error: {0}".format(error)) field.setPalette(self.error_palette) self.errors.add(field) self._check_query() def clear_criteria_error(self, field, tooltip): """Clear the specified widget's error state.""" field.setToolTip(tooltip) field.setPalette(self.orig_palette) self.errors.discard(field) self._check_query() def _check_query(self): button = self.buttonBox.button(QDialogButtonBox.Apply) enabled = not self.errors button.setEnabled(enabled) button.setToolTip("Run the analysis." if enabled else "There are errors in the tab.") # # Save/Load tab # def save(self): raise NotImplementedError def load(self, settings): raise NotImplementedError # # Results runner # def run(self, button): raise NotImplementedError def update_complete(self, count): raise NotImplementedError setools-4.1.1/setoolsgui/apol/apol.qch000066400000000000000000002600001314142262400177620ustar00rootroot00000000000000SQLite format 3@ !!. ( –«A ž 9 ¿ B » 6 Î X Ú d ¿fU#'oindexFileIdIndexFileNameTableCREATE INDEX FileIdIndex ON FileNameTable(FileId)W''oindexFileNameIndexFileNameTableCREATE INDEX FileNameIndex ON FileNameTable(Name)I!aindexNameIndexIndexTableCREATE INDEX NameIndex ON IndexTable(Name)X''qtableMetaDataTableMetaDataTableCREATE TABLE MetaDataTable(Name Text, Value BLOB )t##/tableFolderTableFolderTableCREATE TABLE FolderTable(Id INTEGER PRIMARY KEY, Name Text, NamespaceID INTEGER )| ''7tableFileNameTableFileNameTableCREATE TABLE FileNameTable (FolderId INTEGER, Name TEXT, FileId INTEGER, Title TEXT )t ++tableFileFilterTableFileFilterTable CREATE TABLE FileFilterTable (FilterAttributeId INTEGER, FileId INTEGER )f '' tableFileDataTableFileDataTable CREATE TABLE FileDataTable (Id INTEGER PRIMARY KEY, Data BLOB ) 77#tableFileAttributeSetTableFileAttributeSetTable CREATE TABLE FileAttributeSetTable (Id INTEGER, FilterAttributeId INTEGER ) 33/tableContentsFilterTableContentsFilterTable CREATE TABLE ContentsFilterTable (FilterAttributeId INTEGER, ContentsId INTEGER ){''5tableContentsTableContentsTable CREATE TABLE ContentsTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Data BLOB )x--#tableIndexFilterTableIndexFilterTableCREATE TABLE IndexFilterTable (FilterAttributeId INTEGER, IndexId INTEGER )c))tableIndexItemTableIndexItemTableCREATE TABLE IndexItemTable (Id INTEGER, IndexId INTEGER ) !!‚ tableIndexTableIndexTableCREATE TABLE IndexTable (Id INTEGER PRIMARY KEY, Name TEXT, Identifier TEXT, NamespaceId INTEGER, FileId INTEGER, Anchor TEXT )h##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )h)) tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY,Name TEXT ) ØØ&Scom.github.tresystechnology.setools ÷÷apol ÷÷Apol ûû „óϽ£„) Permission Mappermmap- Information Flow infoflow"A Domain Transition Analysis  DTA  ãûõïéã     TTƒ) †Tindex.htmlApolanalyses.htmlAnalysesinfoflow.html2Information Flow Analysisdta.html4Domain Transition Analysiscomponents.htmlComponentsrules.html Ruleslabeling.htmlLabeling ûû ûû ûû ÖúôîèâÜÖ        ùÜ»‘{M0 !rules.htmlRules 'labeling.htmlLabeling, '?infoflow.htmlInformation Flow Analysis !index.htmlApol( Adta.htmlDomain Transition Analysis +!components.htmlComponents 'analyses.htmlAnalyses ÷÷ doc ÊîÊ"%3CreationDate2012-12-20T12:00:00!qchVersion1.0¡ÙAâ|{–Ì?dŸÿ'Êçß?"Ä[m7¬ $(6¸©à}9¯È#U鑯ölݸF®úÊ(Pz™àhˆK†!þ²3O:)T³Ë¿Ø‘)ÑÁηRù3¤H ÙÅ€/†œäÁŸ¥È© 13±mï•ÈÞÂô´Ô=„ž|>IäöÁ6O\¶¨^¨\/¶î©¬jú*˜SŽÒ5Óˆ¿,ù7“Þª+vÇq-ФqÚ­ôšöGB`Wì;âöü±ò“oé½F‹aŽ~hêèÜRZÅR’¤ïuã-×¢Éê6åÓÎÞ˧#y³[ýßìÒkÃOÿÃܾ¦oé³Hµ†t/l°•';Qé ÈÜÛ¥z!ã‰B/ëRød6•ŽÿòÊ[ýþó§óZ•W䯩$׫‚ñ1f±RQˆ’²V;ÛHµ•ÂO²e³¯ÄᢰTc[¯¥4>/%J»çti–Ž¥ìM{žàïÌŠ¯(e"ÛÑ•4W¹'OZ¿Fñ¥/”ìŒRTP?†ÜŠj¥È@%ÏN©uö/}_+bObˆ¢›˜™E5%5ø²I¿ÍË`A¨½T¬,¨ýï±ìÌrûU.º#ÉUÌâô¡Zû1RBáaYΣ«rs®Í&œ$ *¿mÝï–4ÔžH¥ú„ŒEäXX?P\PÚ¶dLäÈ'Å h9yKö6•Ø"uqTfM®ˆ°¤D#ºö¨ ²7~o“ÀÇòÂ+\hä,zÓmmÿ‡•`=Ça™âË™&~Nsp˜ºHPÎl…ðË€ŒÆ‹õŽ|­ !F_F1I(AJÚïŒ'æ‘ñ:¡*º™ˆ_¨ìÈœàP´Iß9n(ÙO>•Ø™|O?Dê‚Tç˜/-S2’ƒ¹µi™êVTÒEÖu`ú‹þ°÷ÌJB+Ê>Ïj†r%fâÖ‚ÃxÏ”ü¢éÒ6kŠTP&ì³<§ÿÙy5&êÿüFæ{Õ÷TÒãQØ"1p’;8 *tBd™ÌÑR²`¿ÔW¾|ÃvàR=BµLÌ$rìä\•’ΊJ¬Ó6±qkð$ì!5–ó×pΑa^¾Š‹MŠ»•¤»Êº'Îí°–é,SÌ7S Ü[2íi™q˜Ñ­ÙÛ|ÁöæðâÈìÓ—r>ˆX`$vwcîTd+&›Æ,´À–‹âsq@BŽUçֹߥ„²píB‘,H5 ”’jÊ‚5°èýBruLÊ+v§y°©-Wc­‹0!›ûBÖȯCV‘fŒâp#’†¥ŒXˆ…ÏÔí×¶Kʽìdj/ )ÉÇJYÍ%®Š¬2E, ÷s‰ß+±{XN8¿ç ËKâË/þ·wonõçwoþ™BåÃOBWÏÿýúùÃû[ýé—YW|Š…¼â9i‹ˆäwëûŸ>Ñ«»›õ=ENtSèe+Åš“ioE¾.Ѐ;Æøe™Ïàì¹×LZKÁªˆ¯\ƒfåM_¤AwzÈ2Åv’ŠÃ©7 ZÎíî›v%£Ë°‹G<âkJjÈ9Lý9ÆïPÆï£üó^©!-;ÆòŒxç‚«Šø®=‰9oÛÅôØ*¹Xf´iQ"!GjmÑýS¦‰à7åK-¨˜\¸r¥f®”árUK§íÒ£¡¸”'êÑûLÑûW;*sÒ.UÔƒ®PNlÙ¯˜0 ÈÇéÅ>k1©ü¥ÖoS›¯è÷R–qX%Oï8' 5)¥U»ˆ¾î*_Û{rmÓ÷ÝÝ ÿVæé¤>Énb®éØSc¼É´qêddk*Œ@­e„°i‘Ã=/ÏåKõ©ÅTBEB¹š;i.tbQ€ò–Å”¥óÍ“äâ§ôtË@sÇÕqëZ¶øÆÚFš¾·ŸþýÝç‡oÅÌê|Ë)€%ÇìL»¹†±¢Â$Ô4Ñ®“.{×q·¾½î;bZ¦TA ±‚ùåËUñ5£TòB ²X~OúÉt§ôªÃ¬aÖUÅ“f†Q+¦IõÎÍO*ø. Š'W–ÊŽÄ¥df JËaB¯⸆ÇYÒÞÔVæ«ð×è1糨³%,ƒÌ^@ åpQºšäŽL²ø@&ºøLº™ÄiwMÄÁ 0µX"æyÂ}o÷‡> Ó[lÜ× Ñ„#ö'.ÖÚ4„År8úƒ…òHý‹¼1ŽÕ7çdÙ&9wâ U5ª;Ó _A‚ðè<9Jè¦á½É'ucÖ¶áâÇŸ£,ÒÉñbhEY/¤b!:yºƒ€u,Ö‰{ÿB§ ÖßBë9GÆô,8Fj™lŸWŒ“µQYqXº‚'2ËžkNAR,Ê%Óì0û ³§hÝ j®È=ýArw*æjmÑêÑèý"ˆIÉf¿I7䨩(•YKß!0üöž²ÿéÒådòçñõ¯•›È 26éÑEñ÷ n}æÉ«äÊ+å8æCÌêøP&ÌDÆ)ã‘„€ÙW¬¬Wß½T¬×+¡Œ{xöM‡ZTÀ=•5dañ÷óÁ,Zì×YLÈÊ‚‡ŠB;u¬BóˆdÔÚëmgØ=jj®(Õ÷ì>‰Ïqs½&GW³äœë·HØ…~˜,íŠÝK_ïAÃê"—jhéÒR5aŽT2±«Om¦¤\> Ÿ$áKdúVS‰˜!öQ­b·1t¦:a3Ex˜j×wKlŽ®]¯¬s<öšáÞ ˆÎUïaWLy…nL'!À'Žb š^/¶..$=õ&ðŠPô–£ÉgNÆ61}$9@¾”ŠhÍÀ™ÕѧÉj‹[Š›ã´@úVi=UÉ•¶œ‹Á²X=è„ÇÏ+hÍŽs:Öý8$ç“!Ì]S¿x¹"L€ú Æ^ÆÖý9²®Ò•–0¿Ó"îu-æS`G ãiÖ7(GŒ 1‹¥ÿßÊ\À(NüèÙ£"ÆßÀÄU¸è$ÈC͉PùòÈsWnÒ Mïû,€ªœb—L‹Ýe z{ȃ7‚¡®Í§D ¥¦‡¬ÌKF•C<¾œz›z®ã*ñÆ,ptd>¸­f±so•M ”\U¡J Ä‹/FsMN<»ÌÙ¯/ÍÅ­‰œ¶=ƒ2t`o{=[Gý¯Í+ãB>#-}oJ—%éL¶’L$Ę \³RL{Ч2+h½D]q’èl¤‹~‡Tÿ¯J±+ŒÜþöVâÀÿìynÒÉ ¨BfjN‘íÔ—N!‡ê¢ ¹ÆÄÚY¦»V,¤Jûâ¬Áæ‰`Ÿòm‘±øùI‡ª 8„ÎÔ¢Úeu<¼ÍQaäì(>ž _šrÑ÷×í8oÖÄä;8bK0,½æõe' z»Š¯esàR*Œ|ƒm9 “4yà’d¸edê©rï^Ì‚šœ·Ñà qZÀvã͇tÖ  /H"Æ+¹ÑUX–ÕîGôšXR´w?–çã™F¾X“kIlTç§ÖÄ ~ŠP”Y3÷óŒìU‘–r#øüÁâJΨ½|ÎZžboàfÞi¸øü+öO†~öµ]Þ¾E,±µ£ž}0Ͱ˜ßkê¬ÁM¨R—¿½0¾0 ß°Ú®.̓ZÛ<|>Åñê¶L;x€+#Ú‹cà=Îy’ï&òË™ˆql@¢rcðêr“EnÒåS~¼GT¼h|ÉàÀõiÐ~á¶WÙÌoZý9¶0b¾`u¾¿'Ó Ì_íxQ3NPô–>¸ÇÑ5:zñÍ©ªGh8ð é.PÖnï§®wó¬„O9¹ËE’VÏx}ŠŠ×Â)_ݘtH±£Ró¯Æckâ[Á›!t¸gÚÙ‚ö˜ÜÜà³ßöàW,eúÃu @nj€MÁ:‘œÜ&ùÖqåÔx,a‹dšFFDAq`%×!ÀÅ… ¼Wºµ£x¥‰6ß&:¤Ür>XÑ–²\ò@úo:ÀQó=ˆ"9 ȃgÉ 2Å>zzí®<»Ê;Ë€ƒïòÁcã„,ûÎ5j©„&oŸoæð}.\%BW<ÊAB²]ç»krØ·Áôƒ‘Sn¸ËBæM ¥°«í0måB’­ðŽvÔϘ"ø5Yíõj§âþÞs!ZŒƒãìôŠ/jË/ËXÕ¸*ºbOæÓ³‰à"è8 ãJ\›Q?ÆÅW¾rì› #¼ó!£*S],¤bV2 ÆÛ‚>‚ìÏÊwâBS2zëMsq¨Æ”‘8ó±î!ÅóÀx7;}DK[/5ÌjLPÉ4_ÙÒ³ÙVJÛD¹¡OJºÈ_% Îi¶Ã¸­ÝÉü»Tü9/æÙ:•óRßîl>K®‘‚‹Ä{'G„ÜmpÅÎÀâý¬U9ËTé^¥í¡Û\l.ŒN/uG—»ƒ’ˆ¯þ¶Óuqý– ÕéÆåÝÆx ˜Ž úÑœB¼(—á¾ÕI²xªhInóA_’(¾<{&,¾¤ /ƒ¥àwr½¼=]è}ÏÌ®3vì²L‹úÝ^wñÏ .à@B»JÆþi>Ý;¹‰·skq0Z,3ÐÄ!drC)ÖE"ºÇ@?Ք̃ѣ¿Àhê6$f¢[ùt¿¤ögüMÇ-Ë:éjÿÀð„ÃàÔO]æÛ­é6æžBÛá2Ù„jà»Ú‚Dò‡#ÄE†ð£ü½Édd¤§ü¨3vJ®…UŠN7nïd.!ñ·ýx—?_^‰á1‘ÉL¿“Ã5"þw˜düR ªð7D|I!ÃK/³Ìó†l¼x|œ¹—Y;àŽ˜N­ì¥R•ýÈ"}–Wc‘õ‡>çÚÐûÃt'9Ž%Vg›Ä+ÕÎÆv¹‹‰X»:ݶt“û.7/ìmÿ "*Xù åû# þÄå‡\<nxœuU]oã6|ׯئM4®­j HsÀ Àî ¤µÅE$eGýõ%;AqO–©]îìÌìªþi¹¤ç§ }¢ëö†î~½ývãiÇmoq‡iAOO+¢{c(ÇFB‡#w+Z.7Ut2¼¹÷ÎÔëò\Õým> íã“¶ã½:£Û‰î­2SÔ±^# BØÝæåˆ»4Ÿpt'G~³ëu¤½6L­³Ii©QQ·Ô³ñ¤íÞ…A%í,á‰Æ¨íŠ-HÑ!(ßëV™Ê—Šj®HÉŽ$l¹ƒN=Ú^Ù–;ºžQÞPNÒÑï®ç*çøàŽºcÜÐ3©FÉMî÷zí¯3h×èMõø¦myA‘Uh{ ±¨2*1Í`Z7xgÙ‚Ãë4yŽ ’ŸJ¥t3&9pÍ?Ü&jŠñÃÏaÐ1¢kœgäÕâ¢ÒV'­L¤í·¿púü´ýPhA–ÓÉ…ïNfú&2¹ü†ˆJÞ4h••7÷ 8Œ(´ª×Ò_îò•ƒÐOÑ cLJ€Á3Ënæp©Z3v"rN*H\W†â‘©C®¶”ªê,g¹E2Â'¡;‹ÌxêµP/†ÉN‹£÷.€ÙèÆÐr¹£ÑV…郬ÄQÙ/´g•F˜™5U 騃vô>‹=ÚŽƒ™¤™Î!Úºô^­x¢Œ°ÌW*† ¼Ay¡n¶rNã#‰sžSÈŽC*èÔ³CQ«&O'Øø~À¿t{6¥( Žf[ž–1Áâò-Á¸vcœ›¨â„©zÞoéÂÚÿœHd¿Ñí—|ÏèWÅóynŸÙޱ -@ý AëfóâÙÖëfCûà† ‡_aº|8 “CQ˜Õ£2úÝi«êÅš‰àÙó¬(KФĢJzà?òÿ<ð >;U†µâh‰«Pz¯CL¸CÂ[ã"Ö<³²c2´×óTѳòÊÀp1¯‹¹à‚¸ƒKñÇ%ª£\[+êïÿ¼³ŠIW}ÌÏ2¬ƒòW›ËÔÂcÞ#”©ÍªB}0¦ËçSvä/ñ7^m~8 ù¾¹/ˆ±M*¤Lý¸m‹J;:zž´ …À(Òí÷LœåËõ„µ”àîê¾0{¨£ÒFåórMͼ| °\ðÀ¶5²¾œ-Y©Ï·'Õ”4¡Y¾2öÃÊž-¥%4@[ÙªÄ ó’`Õöç ‚¬Z¡Å]tÝ9O6Þ<Õûªy¯áË^ËÁRþÒ :ð%Xea÷åi΄ç¬Š„ÁÊòB$âŠ4ÿ0ž9Ž7œr7xœÅX]oÛ6}ç¯àžjN²fÀRÃ@–¥C€¢CŸ Z¢c®’¨‘TaØß¹üdËùZ[¬A-‘—çÞ{šÿptÄ/tÝu»q|’Mù靿K#mkùRf›Jú¶ñwï.Ž9?/ î×ZŽ%ÒÜÉü˜-ØÜ)WÈůºªÂ~QYå”®øy%ŠÖ*;? +Ø|óúÑex͛׋sþE¶|-…kŒäzÍ—m-ùeµÖ&“¥¬€wy9åVfQ®åÊr·‘\¬TA?f¹\«Jò<œæ°Ýò­r¾Ý¨lÃk£o(áJSÍxc%ö 7\NF2]9£ .²LZ¡¹^ý)3D`Ì …Õ~G>qQåÜ:£2W´ZŒsFÜ$Nž†°þ±‘Ï•ÍkUu;Î@Œ‡Ñ§ŒLµ^ãIåX¤¡äeƒ¼Âi«ü3gÞøS¨Å͇×—|ùé÷˳À‚Èî!9…µ:SÂwÈGâó<¦¦%˜=Å&=Ôé>ßéð " ñp–ç׿].Ÿ€ƒí¡ è…Õ ª4¼PÔÙak²ÿöê]p–O.ß/¯?ýþáê}8nÚŸ'ðºbò=À‰U!ùZáO(ÐP͵“æVº,8ƒ| )9C1Õ¸Xdn‚ÆÒZ'KžÁB‚zBù ¤·° t!i”èérµ[‰[J ½‚¥G‡¢“¡©Í~Ì3ËE€4?ñ?B‡éÞYéÀ¢îí1[Â×L—%VdÂRüŸ<Š>©¯’Ÿƒ‚ Õ—qÞ컺Fîc·¥€†1!Ì(YñK|iO™¯ƒ• ™ Åß×ú“È}—Ä(b©?ûs©x+YL µwoÚ·lÎ%ž—4â¹Ãv×7ÒåІÇRu@T?¥Ø²µN­ò*ô-y/ÊÎÂMß·Àᦔ1â@f>»ñTXƒú™±°®Æ®m>Z9`u ÆÎjJçh‹/pß´¬Öª ›“Ï:¶ sŸŸÐ¥ä½²ãzŠMjØÂÙ}DâÁ)9À/tª,Vl†YV‘ýØuvFâ[mXŒf˜4òl^Â8þy|<Ä”§ñ³~ÜvØÞÀÙÚXJéÈ#šA!ÕH%Q…Lù¶µ×Ð&7Ýu쌂@ƒ©T½ûir0ËÓØz¾6%¡Eʽ|D¾ýojþâP¾!ÞžcC%ŠœÃGáœáÿgzù "ÿ¨‹=å{Æï…|§T^÷1U¨îÈç‡ÞÀ`Q#y&ï;ÂLGæeÜM£»tÌ9Í¿a2–~vCƒFi×1vçʨÛ[ñ4&ÚZÑ0o™KŠ"ج e7Aú ÆNT^“,¯Ïßß\-¯>¼‡¬‡ð »Ç1•G÷n˜ríóÖ°Z´$(õ§Ø'3dk™©uUÄÆ-iÓC%Ö…e"Ýx‚w„ù‘YŠyr-š"¦ ÏX%·d ;HŠt‰S§Ô^ïz]À+ÿ•Ìð2E/LHP4¿女ì/i!¡Qd‰-f­¿""•pêNíŒ v@ûT´£ùÞ6žî9i%„°,ÖXÙ²ÕÀ¦Þ_>ð7Tã3r¿Óý }š!Ú(Ü]–½äé~‡PÂ9Àˆl{>„ÜGRƒ(YéH€ †‡÷£Ø“n`OÙy‡µކs0"ßăHšöX¼›;vÀe6ŒöhRŠÈC¬…'ðŒ>'ÿÿÚ…‚"„Hìxœe‘ÁNÃ0 †ï} sim(ªT*n•Xy€,óÚ 4I:Ö·Çí8$Òÿù·ýKWy ¹Ùë~ˆp­nàîv{Ç0èP – õóÚ¶)jc`õ` ú Èó*QGƒUC£#‹6Q^H&†í/Ì2®êGF«ÔO¢ÜpžNú€Ù2¢´Œ ð,Gmq¥Wä=dŒ£"é$:²vO­¶ÓùkS!JWeËöš„É9òì}ŸÐÏÚöë #C‹úïaí“áÏèê‘È,ñDÉb% §éÉkL#¥¦îJäóþ U„ÆÈR¾CtÔ'~)îf÷WB£×û)¦…W¾Î·,—ÄŸ8¨¨ºUƒ.&xœmAjÃ0E÷>ÅoV-ÔvÓEE˜”B Ë\@$²50ÖIiñí3M²h¡›?¼7Ÿ1m‹­¤%Ó*Ox}Y¿á}Y þ¢°LË3öûm ̸²ŠøüåOÚÖ6¦Reo‡èx)¾˜þ–Ö¿–“ì„QÎ)IÖC5xŒÂ,ß'¸;ünú¤ð™u0Yã²7+Š£ŒÊv¡Î¼²;yv•$âS׸•‘–9kz5ÿê§êîæ‡ÌŽ¢¾êb¡«ÿÚÿô_G±b±  ² } ž ²iƒV3xœMPÁnÂ0 ½÷+¼[‘ ;ì0E•ºŠ[¹”þ ¦d’,N@ùû&´],?û=ûÙúE)è}(ÑÎK‚Ú¬àm³}‡)"† Íâ<ù¹¼Â0ôk€Ž\¡`¼âi Jµ•N6¶c&dÝü‚J/ÛgE²J‡¶ ž€s>ʈX7CZΞÈßî(ŠR Ⱥ ¢Ë$lÛ{Ç)­K2Qð£¸Ï”¬"¼"ÁMŽ6¨÷ÃaõÇ=¡ú:2ž 3™åh—¢x©ÇÏ®ÿÇœd-ìÜÙGƒtò“i÷l7w?:e\ƒ<oxœuAkÂ@…ïùÓ›Jc´‡ÊE‚ô.iœ$ ãκ3±äßwÕRzˆ—7ß{ó’¦°dßÛ´ £j o³ù;J/pÀªuLÜô¯PË)À‚î^hÁpÅÓÒ4OŒZ%Ì‹ò ɺÆd˜vþoEb|¾ðL ÷bÑ¥ÃÐG Ú"ÔLÄß7E¿)-ÏèT>LæcAGqÍ×rìØÿ9L÷w¸AWKÅnnU[ì·«A¾Cµõ³ðŽOøŒ}ÆYv;úé}½¦xÍt6}xœµ[ßs9r~Ç_ø…be­7ÙKJV”ò9vâ”w½ek³©Ô8’ˆ†Þ`F47•ÿ=ýuÌòmâºÚ“f0þÝ_7 »¿¹¾ÖoýáÔ¹í®×WÕRÿÝ«?é‡Î†Sжڵ¾ñÛÓJüøö¥ÖošFóÚ i‰ížlýR__ß«»Þõ½ÿÐn|·7½ó­~ßø£~Óšæ\¸»‘ên÷ê[«è­º;Ü¿9øF‡ápðmÕï¬6k׸þ¤{¯ÍÐ{úÚòó`MWí4ÔþÉv½v#qµ!âA¯m´¶ÕýÑëþt°y OCwðÁj¿!J.h¹Ðô?ÚÆÕ¶íÝæ¤†¶¶ÁufÝÐÚN­ýz°Uok-ôéûbSmzJ/×'môí§Þáme÷DO_=¼[j’ÎU'bã=ѳ_ÍþÐØ•v{³u-Ä2=ËfuØ™Úë8 Ám[¢Mì±ðüNèùÑwÄ#ol_ÝÈêum{ÛíA™XS‰0ËxÜ9R^É}eZKo:¿/6ù­v®ìËíJ¹¶v}ÐnIb ª9˜~ض­ºÓ JœñfkKªtmµzÒusÒ5¶^®tMfÕ/òÆ/FcO% \À[O³öôž=xM2’:{$òÚ ³I4Ž´˜=F ÑȰmzÓÖPN4h¶`á8-ýì»GþºÛ˜Š¼èîæp¯à­¥?³£'µúË»®¾b¿jG”m»…Ú §`ÉcM£:k‚oy@[5CM¯o¿úOãîá®ï¢ßè=Å¥i]؃¨ýÚwäZ¤ÌMc¿Â+ í²õ¾Vpm’Dz14íêè³@Îì6ÎÖ+M:%AI¶`:¼"†Æâ¶ÇΑì H ’üÄ™°Ysð*ÛÖqƒÊÃ4_Wúèú]r”V :?b ¿¨nh,B°Ö;²IgkYG]é½y„4®×µÛl\54=‹f¢F”°†m[èŸLÉQä²1 n“Eª¡ëH¨ e¤ýÃwÚ¯ÿ‹"\W ùï9[*¾> ¬H(¶5IIJ„Ô~ìpO‡ˆe2]§ÊTæ&ñ—Cà)¨ç˜÷•3ˆ&ÙV1WIž¸œ.BŽ`<:ç4·Î?Q6ƒ,ᓳGÄÕªB¦%AÀAPgœ$OŽÎNéûûû_ ¥ùÚŲ¥ infoflow)Permission Map-Information FlowADomain Transition Analysis DTA ‡üêÖɺ¨–‡!rules.html'labeling.html'infoflow.html!index.html dta.html+components.html'analyses.html ÒüöðêäÞØÒ setools-4.1.1/setoolsgui/apol/apol.qhc000066400000000000000000001000001314142262400177530ustar00rootroot00000000000000SQLite format 3@ . ( ² †’$ º  we'' tableSettingsTableSettingsTableCREATE TABLE SettingsTable (Key TEXT PRIMARY KEY, Value BLOB )9M'indexsqlite_autoindex_SettingsTable_1SettingsTableh##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )u##1tableFolderTableFolderTableCREATE TABLE FolderTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Name TEXT )x))+tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY, Name TEXT, FilePath TEXT ) ÏÏ/Scom.github.tresystechnology.setoolsapol.qch ÷÷ doc ÷÷apol ÷÷Apol ûû kÔ»kþâk 9FullTextSearchFallback %CreationTimeX¤¹E ) HideAddressBar- EnableAddressBarA EnableDocumentationManager; HideFilterFunctionality? EnableFilterFunctionalityM)LastShownPagesqthelp://com.github.tresystechnology.setools/doc/index.htmlN+defaultHomepageqthelp://com.github.tresystechnology.setools/doc/index.html#WindowTitleApol Help*-;LastRegisterTime2017-02-15T21:25:41.912 #G\—4{ìµÜÈ9FullTextSearchFallback %CreationTime )HideAddressBar -EnableAddressBarAEnableDocumentationManager;HideFilterFunctionality?EnableFilterFunctionality)LastShownPages+defaultHomepage#WindowTitle- LastRegisterTimesetools-4.1.1/setoolsgui/apol/apol.ui000066400000000000000000000205751314142262400176370ustar00rootroot00000000000000 ApolMainWindow_ui 0 0 800 600 640 480 apol 0 0 0 0 true QTabWidget::North -1 true true 0 0 800 19 &File &Help &Edit Permission &Map Workspace toolBar TopToolBarArea false &Open Policy Open an SELinux Policy Ctrl+O E&xit Ctrl+Q About Apol New Analysis Start a new analysis on this policy. Ctrl+N Cut Ctrl+X Copy Ctrl+C Paste Ctrl+V Open Permission Map Open permission map used for information flow analysis &Rename Tab Rename the active tab. &Close Tab Close the active tab. Ctrl+W Close Policy Close the current policy. Closes all analyses too. Edit Permission Map Save Permission Map Apol Help Save Tab Settings Save the current tab's settings to file. Ctrl+S Load Tab Settings Load settings for the current tab. Ctrl+L Load Workspace Load workspace from file. Ctrl+Shift+L Save Workspace Save workspace to file. Ctrl+Shift+S New Analysis From Settings Start a new analysis using settings from a file. Ctrl+Shift+N exit_apol triggered() ApolMainWindow_ui close() -1 -1 399 299 setools-4.1.1/setoolsgui/apol/boolquery.py000066400000000000000000000163071314142262400207360ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import BoolQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..boolmodel import BooleanTableModel, boolean_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class BoolQueryTab(AnalysisTab): """Bool browser and query tab.""" def __init__(self, parent, policy, perm_map): super(BoolQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = BoolQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.boolquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/boolquery.ui") # populate bool list self.bool_model = SEToolsListModel(self) self.bool_model.item_list = sorted(r for r in self.policy.bools()) self.bools.setModel(self.bool_model) # set up results self.table_results_model = BooleanTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.boolquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.bools.doubleClicked.connect(self.get_detail) self.bools.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Booleans browser # def get_detail(self): # .ui is set for single item selection. index = self.bools.selectedIndexes()[0] item = self.bool_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) boolean_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the Boolean name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Boolean name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_any", "default_true", "default_false", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_any", "default_true", "default_false", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. if self.default_any.isChecked(): self.query.default = None else: self.query.default = self.default_true.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} Boolean(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/boolquery.ui000066400000000000000000000341171314142262400207220ustar00rootroot00000000000000 BoolQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Booleans 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Boolean Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Boolean Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the user's name. Regex 120 0 Default State Any true True False QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander bools name name_regex default_any default_true default_false results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/boundsquery.py000066400000000000000000000165241314142262400212760ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import BoundsQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..boundsmodel import BoundsTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class BoundsQueryTab(AnalysisTab): """Bounds browser and query tab.""" def __init__(self, parent, policy, perm_map): super(BoundsQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = BoundsQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.boundsquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/boundsquery.ui") # set up results self.table_results_model = BoundsTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.parent.palette() self.error_palette = self.parent.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_parent_error() self.clear_child_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.boundsquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.parent.textEdited.connect(self.clear_parent_error) self.parent.editingFinished.connect(self.set_parent) self.parent_regex.toggled.connect(self.set_parent_regex) self.child.textEdited.connect(self.clear_child_error) self.child.editingFinished.connect(self.set_child) self.child_regex.toggled.connect(self.set_child_regex) self.buttonBox.clicked.connect(self.run) # # Parent criteria # def clear_parent_error(self): self.clear_criteria_error(self.parent, "Match the parent type.") def set_parent(self): try: self.query.parent = self.parent.text() except Exception as ex: self.log.error("Type parent error: {0}".format(ex)) self.set_criteria_error(self.parent, ex) def set_parent_regex(self, state): self.log.debug("Setting parent_regex {0}".format(state)) self.query.parent_regex = state self.clear_parent_error() self.set_parent() # # Child criteria # def clear_child_error(self): self.clear_criteria_error(self.child, "Match the child type.") def set_child(self): try: self.query.child = self.child.text() except Exception as ex: self.log.error("Type child error: {0}".format(ex)) self.set_criteria_error(self.child, ex) def set_child_regex(self, state): self.log.debug("Setting child_regex {0}".format(state)) self.query.child_regex = state self.clear_child_error() self.set_child() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "typebounds", "parent_regex", "child_regex"]) save_lineedits(self, settings, ["parent", "child"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "typebounds", "parent_regex", "child_regex"]) load_lineedits(self, settings, ["parent", "child"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.parent_regex = self.parent_regex.isChecked() self.query.child_regex = self.child_regex.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} bound(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/boundsquery.ui000066400000000000000000000420741314142262400212620ustar00rootroot00000000000000 BoundsQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Bounds Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 Clear false Qt::Horizontal 40 20 Select All false typebounds true 16777215 100 Parent (Bounding) Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 true Use regular expressions to match the context's role. Regex 16777215 100 Child (Bounded) Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the context's type. Regex QDialogButtonBox::Apply SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander typebounds clear_ruletypes all_ruletypes parent parent_regex child child_regex results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776
setools-4.1.1/setoolsgui/apol/categoryquery.py000066400000000000000000000162701314142262400216170ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import CategoryQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsmodel import MLSComponentTableModel, category_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class CategoryQueryTab(AnalysisTab): """Category browser and query tab.""" def __init__(self, parent, policy, perm_map): super(CategoryQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = CategoryQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.categoryquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/categoryquery.ui") # populate category list self.category_model = SEToolsListModel(self) self.category_model.item_list = sorted(self.policy.categories()) self.cats.setModel(self.category_model) # set up results self.table_results_model = MLSComponentTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.categoryquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.cats.doubleClicked.connect(self.get_detail) self.cats.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Category browser # def get_detail(self): # .ui is set for single item selection. index = self.cats.selectedIndexes()[0] item = self.category_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) category_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the category name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Category name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} categories found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/categoryquery.ui000066400000000000000000000312731314142262400216040ustar00rootroot00000000000000 CategoryQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Categories 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Categories Browser 0 0 16777215 16777215 Search Criteria QDialogButtonBox::Apply 16777215 120 Category Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander cats name name_regex results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/choose_analysis.ui000066400000000000000000000050571314142262400220650ustar00rootroot00000000000000 ChooseAnalysis 0 0 400 421 New Analysis Choose a new analysis to start: QAbstractItemView::SingleSelection true true 1 false Analyses Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox rejected() ChooseAnalysis reject() 316 260 286 274 buttonBox accepted() ChooseAnalysis accept() 199 400 199 210 analysisTypes itemDoubleClicked(QTreeWidgetItem*,int) ChooseAnalysis accept() 199 206 199 210 setools-4.1.1/setoolsgui/apol/chooseanalysis.py000066400000000000000000000145411314142262400217370ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QDialog, QTreeWidgetItem from ..widget import SEToolsWidget # Analysis tabs: from .boolquery import BoolQueryTab from .boundsquery import BoundsQueryTab from .categoryquery import CategoryQueryTab from .commonquery import CommonQueryTab from .constraintquery import ConstraintQueryTab from .defaultquery import DefaultQueryTab from .dta import DomainTransitionAnalysisTab from .fsusequery import FSUseQueryTab from .genfsconquery import GenfsconQueryTab from .infoflow import InfoFlowAnalysisTab from .initsidquery import InitialSIDQueryTab from .mlsrulequery import MLSRuleQueryTab from .netifconquery import NetifconQueryTab from .nodeconquery import NodeconQueryTab from .objclassquery import ObjClassQueryTab from .portconquery import PortconQueryTab from .rbacrulequery import RBACRuleQueryTab from .rolequery import RoleQueryTab from .sensitivityquery import SensitivityQueryTab from .summary import SummaryTab from .terulequery import TERuleQueryTab from .typeattrquery import TypeAttributeQueryTab from .typequery import TypeQueryTab from .userquery import UserQueryTab # TODO: is there a better way than hardcoding this while still being safe? tab_map = {"BoolQueryTab": BoolQueryTab, "BoundsQueryTab": BoundsQueryTab, "CategoryQueryTab": CategoryQueryTab, "CommonQueryTab": CommonQueryTab, "ConstraintQueryTab": ConstraintQueryTab, "DefaultQueryTab": DefaultQueryTab, "DomainTransitionAnalysisTab": DomainTransitionAnalysisTab, "FSUseQueryTab": FSUseQueryTab, "GenfsconQueryTab": GenfsconQueryTab, "InfoFlowAnalysisTab": InfoFlowAnalysisTab, "InitialSIDQueryTab": InitialSIDQueryTab, "MLSRuleQueryTab": MLSRuleQueryTab, "NetifconQueryTab": NetifconQueryTab, "NodeconQueryTab": NodeconQueryTab, "ObjClassQueryTab": ObjClassQueryTab, "PortconQueryTab": PortconQueryTab, "RBACRuleQueryTab": RBACRuleQueryTab, "RoleQueryTab": RoleQueryTab, "SensitivityQueryTab": SensitivityQueryTab, "SummaryTab": SummaryTab, "TERuleQueryTab": TERuleQueryTab, "TypeAttributeQueryTab": TypeAttributeQueryTab, "TypeQueryTab": TypeQueryTab, "UserQueryTab": UserQueryTab} class ChooseAnalysis(SEToolsWidget, QDialog): """ Dialog for choosing a new analysis The below class attributes are used for populating the GUI contents and mapping them to the appropriate tab widget class for the analysis. """ def __init__(self, parent): super(ChooseAnalysis, self).__init__(parent) self.parent = parent self.setupUi() def setupUi(self): self.load_ui("apol/choose_analysis.ui") def show(self, mls): analysis_map = {"Domain Transition Analysis": DomainTransitionAnalysisTab, "Information Flow Analysis": InfoFlowAnalysisTab} components_map = {"Booleans": BoolQueryTab, "Commons": CommonQueryTab, "Roles": RoleQueryTab, "Object Classes": ObjClassQueryTab, "Types": TypeQueryTab, "Type Attributes": TypeAttributeQueryTab, "Users": UserQueryTab} rule_map = {"Constraints": ConstraintQueryTab, "RBAC Rules": RBACRuleQueryTab, "TE Rules": TERuleQueryTab} labeling_map = {"Fs_use_* Statements": FSUseQueryTab, "Genfscon Statements": GenfsconQueryTab, "Initial SID Statements": InitialSIDQueryTab, "Netifcon Statements": NetifconQueryTab, "Nodecon Statements": NodeconQueryTab, "Portcon Statements": PortconQueryTab} general_choices = {"Summary": SummaryTab} other_choices = {"Bounds": BoundsQueryTab, "Defaults": DefaultQueryTab} analysis_choices = {"Components": components_map, "Rules": rule_map, "Analyses": analysis_map, "Labeling": labeling_map, "General": general_choices, "Other": other_choices} if mls: rule_map["MLS Rules"] = MLSRuleQueryTab components_map["Categories"] = CategoryQueryTab components_map["Sensitivities"] = SensitivityQueryTab # populate the item list: self.analysisTypes.clear() for groupname, group in analysis_choices.items(): groupitem = QTreeWidgetItem(self.analysisTypes) groupitem.setText(0, groupname) groupitem._tab_class = None for entryname, cls in group.items(): item = QTreeWidgetItem(groupitem) item.setText(0, entryname) item._tab_class = cls groupitem.addChild(item) self.analysisTypes.expandAll() self.analysisTypes.sortByColumn(0, Qt.AscendingOrder) super(ChooseAnalysis, self).show() def accept(self, item=None): try: if not item: # .ui is set for single item selection. item = self.analysisTypes.selectedItems()[0] title = item.text(0) self.parent.create_new_analysis(title, item._tab_class) except (IndexError, TypeError): # IndexError: nothing is selected # TypeError: one of the group items was selected. pass else: super(ChooseAnalysis, self).accept() setools-4.1.1/setoolsgui/apol/commonquery.py000066400000000000000000000202771314142262400212740ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import CommonQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..commonmodel import CommonTableModel, common_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class CommonQueryTab(AnalysisTab): """Common browser and query tab.""" def __init__(self, parent, policy, perm_map): super(CommonQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = CommonQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.commonquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/commonquery.ui") # populate commons list self.common_model = SEToolsListModel(self) self.common_model.item_list = sorted(c for c in self.policy.commons()) self.commons.setModel(self.common_model) # populate perm list self.perms_model = SEToolsListModel(self) perms = set() for com in self.policy.commons(): perms.update(com.perms) self.perms_model.item_list = sorted(perms) self.perms.setModel(self.perms_model) # set up results self.table_results_model = CommonTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.commonquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.commons.doubleClicked.connect(self.get_detail) self.commons.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.buttonBox.clicked.connect(self.run) # # Class browser # def get_detail(self): # .ui is set for single item selection. index = self.commons.selectedIndexes()[0] item = self.common_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) common_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the common name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Common name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.perms_equal = self.perms_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} common(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/commonquery.ui000066400000000000000000000403241314142262400212540ustar00rootroot00000000000000 CommonQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Common Permission Sets 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Common Browser 0 0 16777215 16777215 Search Criteria Permission Set 0 0 250 16777215 A matching common will have the selected permissions. QAbstractItemView::ExtendedSelection Clear A matching common will a permission set equal to the selected permissions. Equal Qt::Horizontal 40 20 Invert Qt::Vertical 20 40 QDialogButtonBox::Apply 16777215 120 Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander commons name name_regex perms clear_perms invert_perms perms_equal results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226 clear_perms clicked() perms clearSelection() 592 216 442 276
setools-4.1.1/setoolsgui/apol/constraintquery.py000066400000000000000000000314441314142262400221660ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import ConstraintQuery from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..constraintmodel import ConstraintTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class ConstraintQueryTab(AnalysisTab): """A constraint query.""" def __init__(self, parent, policy, perm_map): super(ConstraintQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = ConstraintQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.constraintquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/constraintquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # setup indications of errors self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_user_error() self.clear_type_error() self.clear_role_error() # set up results self.table_results_model = ConstraintTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.constraintquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_user_regex(self.user_regex.isChecked()) self.set_role_regex(self.role_regex.isChecked()) self.set_type_regex(self.type_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # MLS constraints available only if policy is MLS if not self.policy.mls: self.mlsconstrain.setEnabled(False) self.mlsvalidatetrans.setEnabled(False) self.mlsconstrain.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) # # Ruletype criteria # def _set_ruletypes(self, value): self.constrain.setChecked(value) self.validatetrans.setChecked(value) if self.policy.mls: self.mlsconstrain.setChecked(value) self.mlsvalidatetrans.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes self.perms_model.set_classes(selected_classes) def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match constraints that have a user in the expression.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("User error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match constraints that have a role in the expression.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match constraints that have a type in the expression.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain", "mlsconstrain", "validatetrans", "mlsvalidatetrans", "user_regex", "role_regex", "type_regex", "perms_subset"]) save_lineedits(self, settings, ["user", "role", "type_"]) save_listviews(self, settings, ["tclass", "perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain", "mlsconstrain", "validatetrans", "mlsvalidatetrans", "user_regex", "role_regex", "type_regex", "perms_subset"]) load_lineedits(self, settings, ["user", "role", "type_"]) load_listviews(self, settings, ["tclass", "perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.constrain, self.mlsconstrain, self.validatetrans, self.mlsvalidatetrans]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.perms_subset = self.perms_subset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} constraint(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions or expression column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(2) > 400: header.resizeSection(2, 400) if header.sectionSize(3) > 400: header.resizeSection(3, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/constraintquery.ui000066400000000000000000000640621314142262400221550ustar00rootroot00000000000000 ConstraintQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Constraint Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 MLSValidatetrans MLSConstrain Qt::Horizontal 40 20 Select All Constrain true Clear false Validatetrans false 16777215 100 Role In Expression 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 true Use regular expressions to match the context's role. Regex QDialogButtonBox::Apply Object Class 0 0 250 16777215 Match the object class of the constraint. QAbstractItemView::ExtendedSelection Clear Qt::Horizontal 40 20 Qt::Vertical 20 40 Invert 16777215 100 Type In Expression 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the context's type. Regex Permission Set 6 6 6 6 3 Invert Clear Qt::Horizontal 40 20 A matching rule will have all of the selected permissions. Match All Qt::Vertical 20 40 0 0 250 16777215 The list of permissions common to selected object classes. QAbstractItemView::ExtendedSelection User In Expression 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 133 20 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander constrain mlsconstrain validatetrans mlsvalidatetrans clear_ruletypes all_ruletypes role type_ clear_class invert_class perms clear_perms invert_perms perms_subset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 clear_perms clicked() perms clearSelection() 565 312 448 330 clear_class clicked() tclass clearSelection() 282 230 132 254
setools-4.1.1/setoolsgui/apol/defaultquery.py000066400000000000000000000173451314142262400214320ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import DefaultQuery, DefaultValue, DefaultRangeValue from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..defaultmodel import DefaultTableModel from .analysistab import AnalysisTab from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_comboboxes, load_listviews, load_textedits, \ save_checkboxes, save_comboboxes, save_listviews, save_textedits class DefaultQueryTab(AnalysisTab): """Default browser and query tab.""" def __init__(self, parent, policy, perm_map): super(DefaultQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = DefaultQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.defaultquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/defaultquery.ui") # set up results self.table_results_model = DefaultTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # these two lists have empty string as their first item # (in the .ui file): # populate default value list for i, e in enumerate(DefaultValue, start=1): self.default_value.insertItem(i, e.name, e) # populate default range value list for i, e in enumerate(DefaultRangeValue, start=1): self.default_range_value.insertItem(i, e.name, e) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.defaultquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.default_range_value.setEnabled(self.default_range.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.default_range.toggled.connect(self.default_range_value.setEnabled) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.buttonBox.clicked.connect(self.run) # # Ruletype criteria # def _set_ruletypes(self, value): self.default_user.setChecked(value) self.default_role.setChecked(value) self.default_type.setChecked(value) self.default_range.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_user", "default_role", "default_type", "default_range"]) save_comboboxes(self, settings, ["default_value", "default_range_value"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_user", "default_role", "default_type", "default_range"]) load_comboboxes(self, settings, ["default_value", "default_range_value"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.default_user, self.default_role, self.default_type, self.default_range]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.default = self.default_value.currentData(Qt.UserRole) if self.default_range_value.isEnabled(): self.query.default_range = self.default_range_value.currentData(Qt.UserRole) else: self.query.default_range = None # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} default(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/defaultquery.ui000066400000000000000000000444451314142262400214200ustar00rootroot00000000000000 DefaultQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 770 842 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Default Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 Clear false Qt::Horizontal 40 20 Select All true default_user true default_role true default_type true default_range true QDialogButtonBox::Apply Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection 16777215 100 Default 6 6 6 6 3 0 0 0 0 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander default_user default_type default_role default_range clear_ruletypes all_ruletypes tclass clear_class invert_class default_value default_range_value results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 clear_class clicked() tclass clearSelection() 318 164 150 188
setools-4.1.1/setoolsgui/apol/dta.py000066400000000000000000000462141314142262400174650ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import pyqtSignal, Qt, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog, \ QTreeWidgetItem from setools import DomainTransitionAnalysis from ..logtosignal import LogHandlerToSignal from .analysistab import AnalysisTab from .excludetypes import ExcludeTypes from .exception import TabFieldError from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \ save_checkboxes, save_spinboxes, save_lineedits, save_textedits class DomainTransitionAnalysisTab(AnalysisTab): """A domain transition analysis tab.""" def __init__(self, parent, policy, perm_map): super(DomainTransitionAnalysisTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = DomainTransitionAnalysis(policy) self.query.source = None self.query.target = None self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.dta").removeHandler(self.handler) def setupUi(self): self.log.debug("Initializing UI.") self.load_ui("apol/dta.ui") # set up source/target autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.source.setCompleter(self.type_completion) self.target.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() # set up processing thread self.thread = ResultsUpdater(self.query) self.thread.raw_line.connect(self.raw_results.appendPlainText) self.thread.finished.connect(self.update_complete) self.thread.trans.connect(self.reset_browser) # set up browser thread self.browser_thread = BrowserUpdater(self.query) self.browser_thread.trans.connect(self.add_browser_children) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.setCancelButton(None) self.busy.reset() # update busy dialog from DTA INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.dta").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.max_path_length.setEnabled(self.all_paths.isChecked()) self.source.setEnabled(not self.flows_in.isChecked()) self.target.setEnabled(not self.flows_out.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) self.browser_tab.setEnabled(self.flows_in.isChecked() or self.flows_out.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.all_paths.toggled.connect(self.all_paths_toggled) self.flows_in.toggled.connect(self.flows_in_toggled) self.flows_out.toggled.connect(self.flows_out_toggled) self.reverse.stateChanged.connect(self.reverse_toggled) self.exclude_types.clicked.connect(self.choose_excluded_types) self.browser.currentItemChanged.connect(self.browser_item_selected) # # Analysis mode # def all_paths_toggled(self, value): self.clear_source_error() self.clear_target_error() self.max_path_length.setEnabled(value) def flows_in_toggled(self, value): self.clear_source_error() self.clear_target_error() self.source.setEnabled(not value) self.reverse.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) if value: self.reverse_old = self.reverse.isChecked() self.reverse.setChecked(True) else: self.reverse.setChecked(self.reverse_old) def flows_out_toggled(self, value): self.clear_source_error() self.clear_target_error() self.target.setEnabled(not value) self.reverse.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) if value: self.reverse_old = self.reverse.isChecked() self.reverse.setChecked(False) else: self.reverse.setChecked(self.reverse_old) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "The source domain of the analysis.") def set_source(self): try: # look up the type here, so invalid types can be caught immediately text = self.source.text() if text: self.query.source = self.policy.lookup_type(text) else: self.query.source = None except Exception as ex: self.log.error("Source domain error: {0}".format(str(ex))) self.set_criteria_error(self.source, ex) # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "The target domain of the analysis.") def set_target(self): try: # look up the type here, so invalid types can be caught immediately text = self.target.text() if text: self.query.target = self.policy.lookup_type(text) else: self.query.target = None except Exception as ex: self.log.error("Target domain error: {0}".format(str(ex))) self.set_criteria_error(self.target, ex) # # Options # def choose_excluded_types(self): chooser = ExcludeTypes(self, self.policy) chooser.show() def reverse_toggled(self, value): self.query.reverse = value # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out", "reverse"]) save_lineedits(self, settings, ["source", "target"]) save_spinboxes(self, settings, ["max_path_length", "limit_paths"]) save_textedits(self, settings, ["notes"]) settings["exclude"] = [str(t) for t in self.query.exclude] return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out", "reverse"]) load_lineedits(self, settings, ["source", "target"]) load_spinboxes(self, settings, ["max_path_length", "limit_paths"]) load_textedits(self, settings, ["notes"]) try: self.query.exclude = settings["exclude"] except KeyError: self.log.warning("Excluded types criteria missing from settings file.") # # Infoflow browser # def _new_browser_item(self, type_, parent, rules=None, children=None): # build main item item = QTreeWidgetItem(parent if parent else self.browser) item.setText(0, str(type_)) item.type_ = type_ item.children = children if children else [] item.rules = rules if rules else [] item.child_populated = children is not None # add child items for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.setExpanded(children is not None) self.log.debug("Built item for {0} with {1} children and {2} rules".format( type_, len(item.children), len(item.rules))) return item def reset_browser(self, root_type, out, children): self.log.debug("Resetting browser.") # clear results self.browser.clear() self.browser_details.clear() # save browser details independent # from main analysis UI settings self.browser_root_type = root_type self.browser_mode = out root = self._new_browser_item(self.browser_root_type, self.browser, children=children) self.browser.insertTopLevelItem(0, root) def browser_item_selected(self, current, previous): if not current: # browser is being reset return self.log.debug("{0} selected in browser.".format(current.type_)) self.browser_details.clear() try: parent_type = current.parent().type_ except AttributeError: # should only hit his on the root item pass else: self.browser_details.appendPlainText("Domain Transitions {0} {1} {2}\n".format( current.parent().type_, "->" if self.browser_mode else "<-", current.type_)) print_transition(self.browser_details.appendPlainText, current.rules) self.browser_details.moveCursor(QTextCursor.Start) if not current.child_populated: self.busy.setLabelText("Gathering additional browser details for {0}...".format( current.type_)) self.busy.show() self.browser_thread.out = self.browser_mode self.browser_thread.type_ = current.type_ self.browser_thread.start() def add_browser_children(self, children): item = self.browser.currentItem() item.children = children self.log.debug("Adding children for {0}".format(item.type_)) for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.child_populated = True self.busy.reset() # # Results runner # def run(self, button): # right now there is only one button. fail = False if self.source.isEnabled() and not self.query.source: self.set_criteria_error(self.source, "A source domain is required") if self.target.isEnabled() and not self.query.target: self.set_criteria_error(self.target, "A target domain is required.") if self.errors: return for mode in [self.all_paths, self.all_shortest_paths, self.flows_in, self.flows_out]: if mode.isChecked(): break self.query.mode = mode.objectName() self.query.max_path_len = self.max_path_length.value() self.query.limit = self.limit_paths.value() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self): if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) if self.flows_in.isChecked() or self.flows_out.isChecked(): # move to browser tab for transitions in/out self.results_frame.setCurrentIndex(1) else: self.results_frame.setCurrentIndex(0) self.busy.reset() def sort_transition(trans): """Sort the rules of a transition in-place.""" trans.transition.sort() trans.setexec.sort() trans.entrypoints.sort() trans.dyntransition.sort() trans.setcurrent.sort() for e in trans.entrypoints: e.entrypoint.sort() e.execute.sort() e.type_transition.sort() def print_transition(renderer, trans): """ Raw rendering of a domain transition. Parameters: renderer A callable which will render the output, e.g. print trans A step (transition object) generated by the DTA. """ if trans.transition: renderer("Domain transition rule(s):") for t in trans.transition: renderer(str(t)) if trans.setexec: renderer("\nSet execution context rule(s):") for s in trans.setexec: renderer(str(s)) for entrypoint in trans.entrypoints: renderer("\nEntrypoint {0}:".format(entrypoint.name)) renderer("\tDomain entrypoint rule(s):") for e in entrypoint.entrypoint: renderer("\t{0}".format(e)) renderer("\n\tFile execute rule(s):") for e in entrypoint.execute: renderer("\t{0}".format(e)) if entrypoint.type_transition: renderer("\n\tType transition rule(s):") for t in entrypoint.type_transition: renderer("\t{0}".format(t)) renderer("") if trans.dyntransition: renderer("Dynamic transition rule(s):") for d in trans.dyntransition: renderer(str(d)) renderer("\nSet current process context rule(s):") for s in trans.setcurrent: renderer(str(s)) renderer("") renderer("") class ResultsUpdater(QThread): """ Thread for processing queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: raw_line (str) A string to be appended to the raw results. trans (str, bool, list) Initial information for populating the transitions browser. """ raw_line = pyqtSignal(str) trans = pyqtSignal(str, bool, list) def __init__(self, query): super(ResultsUpdater, self).__init__() self.query = query self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): """Run the query and update results.""" assert self.query.limit, "Code doesn't currently handle unlimited (limit=0) paths." self.out = self.query.mode == "flows_out" if self.query.mode == "all_paths": self.transitive(self.query.all_paths(self.query.source, self.query.target, self.query.max_path_len)) elif self.query.mode == "all_shortest_paths": self.transitive(self.query.all_shortest_paths(self.query.source, self.query.target)) elif self.query.mode == "flows_out": self.direct(self.query.transitions(self.query.source)) else: # flows_in self.direct(self.query.transitions(self.query.target)) def transitive(self, paths): i = 0 for i, path in enumerate(paths, start=1): self.raw_line.emit("Domain transition path {0}:".format(i)) for stepnum, step in enumerate(path, start=1): self.raw_line.emit("Step {0}: {1} -> {2}\n".format(stepnum, step.source, step.target)) sort_transition(step) print_transition(self.raw_line.emit, step) if QThread.currentThread().isInterruptionRequested() or (i >= self.query.limit): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} domain transition path(s) found.".format(i)) self.log.info("{0} domain transition path(s) found.".format(i)) def direct(self, transitions): i = 0 child_types = [] for i, step in enumerate(transitions, start=1): self.raw_line.emit("Transition {0}: {1} -> {2}\n".format(i, step.source, step.target)) sort_transition(step) print_transition(self.raw_line.emit, step) # Generate results for flow browser if self.out: child_types.append((step.target, step)) else: child_types.append((step.source, step)) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} domain transition(s) found.".format(i)) self.log.info("{0} domain transition(s) found.".format(i)) # Update browser: root_type = self.query.source if self.out else self.query.target self.trans.emit(str(root_type), self.out, sorted(child_types)) class BrowserUpdater(QThread): """ Thread for processing additional analysis for the browser. Parameters: query The query object model The model for the results Qt signals: trans A list of child types to render in the transitions browser. """ trans = pyqtSignal(list) def __init__(self, query): super(BrowserUpdater, self).__init__() self.query = query self.type_ = None self.out = None self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): transnum = 0 child_types = [] for transnum, trans in enumerate(self.query.transitions(self.type_), start=1): # Generate results for browser sort_transition(trans) if self.out: child_types.append((trans.target, trans)) else: child_types.append((trans.source, trans)) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.log.debug("{0} additional domain transition(s) found.".format(transnum)) # Update browser: self.trans.emit(sorted(child_types)) setools-4.1.1/setoolsgui/apol/dta.ui000066400000000000000000000467021314142262400174540ustar00rootroot00000000000000 DomainTransitionAnalysisTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 Options 3 3 6 6 6 6 Limit results: 1 1000 20 Excluded Types: Edit... Reverse: Analyze reverse (parent) domain transitions instead of forward (child) domain transitions. 16777215 100 Target Domain 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 16777215 100 Source Domain 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 QDialogButtonBox::Apply Analysis Mode 6 6 6 6 3 The limit for path length. steps 1 3 All domain transitions into the target domain will be shown. Transitions into the target domain All paths from the source domain to the target domain, up to the specified maximum length, will be shown. All paths up to All shortest paths from the source domain to the target domain will be shown. Shortest paths true All domain transitions out of the source domain will be shown. Transitions out of the source domain source_criteria target_criteria buttonBox groupBox groupBox_2 0 0 16777215 20 12 75 true Domain Transition Analysis Show: Qt::Horizontal 40 20 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 1 0 0 0 Raw Results 3 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Browser Qt::Horizontal 1 0 Type 4 0 Monospace SEToolsTreeWidget QTreeWidget
setoolsgui/treeview.h
criteria_expander notes_expander source target all_shortest_paths all_paths max_path_length flows_out flows_in reverse limit_paths exclude_types results_frame raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 589 16 386 164 notes_expander toggled(bool) notes setVisible(bool) 732 16 386 705
setools-4.1.1/setoolsgui/apol/exception.py000066400000000000000000000015151314142262400207060ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # class TabFieldError(RuntimeError): """Exception when trying to save a tab that has errors.""" pass setools-4.1.1/setoolsgui/apol/exclude_types.ui000066400000000000000000000117521314142262400215560ustar00rootroot00000000000000 Dialog 0 0 619 340 Exclude Types From Analysis 0 0 16777215 20 11 75 true Included Types 0 0 16777215 20 11 75 true Excluded Types Qt::Vertical 20 40 Exclude selected types. Include selected types. Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok 150 16777215 Filter types by attribute: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QAbstractItemView::ExtendedSelection QAbstractItemView::ExtendedSelection buttonBox accepted() Dialog accept() 248 254 157 274 buttonBox rejected() Dialog reject() 316 260 286 274 setools-4.1.1/setoolsgui/apol/excludetypes.py000066400000000000000000000123551314142262400214320ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from PyQt5.QtCore import Qt, QSortFilterProxyModel from PyQt5.QtWidgets import QDialog from ..models import SEToolsListModel from ..widget import SEToolsWidget class ExcludeTypes(SEToolsWidget, QDialog): """Dialog for choosing excluded types.""" def __init__(self, parent, policy): super(ExcludeTypes, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.policy = policy self.initial_excluded_list = copy.copy(self.parent.query.exclude) self.setupUi() def setupUi(self): self.load_ui("apol/exclude_types.ui") # populate the attribute combo box: self.attr_model = SEToolsListModel(self) self.attr_model.item_list = [""] + sorted(self.policy.typeattributes()) self.attr.setModel(self.attr_model) # populate the models: self.included_model = SEToolsListModel(self) self.included_model.item_list = [t for t in self.policy.types() if t not in self.initial_excluded_list] self.included_sort = FilterByAttributeProxy(self) self.included_sort.setSourceModel(self.included_model) self.included_sort.sort(0, Qt.AscendingOrder) self.included_types.setModel(self.included_sort) self.excluded_model = SEToolsListModel(self) self.excluded_model.item_list = self.initial_excluded_list self.excluded_sort = FilterByAttributeProxy(self) self.excluded_sort.setSourceModel(self.excluded_model) self.excluded_sort.sort(0, Qt.AscendingOrder) self.excluded_types.setModel(self.excluded_sort) # connect signals self.exclude_a_type.clicked.connect(self.exclude_clicked) self.include_a_type.clicked.connect(self.include_clicked) self.attr.currentIndexChanged.connect(self.set_attr_filter) def include_clicked(self): included_scroll_pos = self.included_types.verticalScrollBar().value() excluded_scroll_pos = self.excluded_types.verticalScrollBar().value() selected_types = [] for index in self.excluded_types.selectionModel().selectedIndexes(): source_index = self.excluded_sort.mapToSource(index) item = self.excluded_model.data(source_index, Qt.UserRole) self.included_model.append(item) selected_types.append(item) self.log.debug("Including {0}".format(selected_types)) for item in selected_types: self.excluded_model.remove(item) self.included_types.verticalScrollBar().setValue(included_scroll_pos) self.excluded_types.verticalScrollBar().setValue(excluded_scroll_pos) def exclude_clicked(self): included_scroll_pos = self.included_types.verticalScrollBar().value() excluded_scroll_pos = self.excluded_types.verticalScrollBar().value() selected_types = [] for index in self.included_types.selectionModel().selectedIndexes(): source_index = self.included_sort.mapToSource(index) item = self.included_model.data(source_index, Qt.UserRole) self.excluded_model.append(item) selected_types.append(item) self.log.debug("Excluding {0}".format(selected_types)) for item in selected_types: self.included_model.remove(item) self.included_types.verticalScrollBar().setValue(included_scroll_pos) self.excluded_types.verticalScrollBar().setValue(excluded_scroll_pos) def set_attr_filter(self, row): index = self.attr_model.index(row) attr = self.attr_model.data(index, Qt.UserRole) self.log.debug("Attribute set to {0!r}".format(attr)) self.included_sort.attr = attr self.excluded_sort.attr = attr def accept(self): self.log.debug("Chosen for exclusion: {0!r}".format(self.excluded_model.item_list)) self.parent.query.exclude = self.excluded_model.item_list super(ExcludeTypes, self).accept() class FilterByAttributeProxy(QSortFilterProxyModel): """Filter a list of types by attribute membership.""" _attr = None @property def attr(self): return self._attr @attr.setter def attr(self, value): self._attr = value self.invalidateFilter() def filterAcceptsRow(self, row, parent): if self.attr: source = self.sourceModel() index = source.index(row) item = source.data(index, Qt.UserRole) if item not in self.attr: return False return True setools-4.1.1/setoolsgui/apol/fsusequery.py000066400000000000000000000303761314142262400211320ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import FSUseQuery from ..logtosignal import LogHandlerToSignal from ..fsusemodel import FSUseTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class FSUseQueryTab(AnalysisTab): """A fs_use_* rule query.""" def __init__(self, parent, policy, perm_map): super(FSUseQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = FSUseQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.fsusequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/fsusequery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_fs_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = FSUseTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.fsusequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_fs_regex(self.fs_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.fs.textEdited.connect(self.clear_fs_error) self.fs.editingFinished.connect(self.set_fs) self.fs_regex.toggled.connect(self.set_fs_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Ruletype criteria # def _set_ruletypes(self, value): self.fs_use_xattr.setChecked(value) self.fs_use_trans.setChecked(value) self.fs_use_task.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # FS criteria # def clear_fs_error(self): self.clear_criteria_error(self.fs, "Match the filesystem type.") def set_fs(self): try: self.query.fs = self.fs.text() except Exception as ex: self.log.error("Filesystem type error: {0}".format(ex)) self.set_criteria_error(self.fs, ex) def set_fs_regex(self, state): self.log.debug("Setting fs_regex {0}".format(state)) self.query.fs_regex = state self.clear_fs_error() self.set_fs() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.fs_use_xattr, self.fs_use_trans, self.fs_use_task]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} fs_use_* statment(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/fsusequery.ui000066400000000000000000000614501314142262400211140ustar00rootroot00000000000000 FSUseQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true fs_use_* Statements 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 Filesystem Type Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Qt::Horizontal 40 20 fs_use_xattr true Clear false fs_use_task true fs_use_trans true QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 role_criteria type_criteria user_critera ruletype_criteria fs_criteria range_criteria buttonBox Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander fs_use_xattr fs_use_task fs_use_trans clear_ruletypes all_ruletypes fs fs_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/genfsconquery.py000066400000000000000000000304171314142262400216030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import GenfsconQuery from ..logtosignal import LogHandlerToSignal from ..genfsconmodel import GenfsconTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class GenfsconQueryTab(AnalysisTab): """A fs_use_* rule query.""" def __init__(self, parent, policy, perm_map): super(GenfsconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = GenfsconQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.genfsconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/genfsconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_fs_error() self.clear_path_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = GenfsconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.genfsconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_fs_regex(self.fs_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.fs.textEdited.connect(self.clear_fs_error) self.fs.editingFinished.connect(self.set_fs) self.fs_regex.toggled.connect(self.set_fs_regex) self.path.textEdited.connect(self.clear_path_error) self.path.editingFinished.connect(self.set_path) self.path_regex.toggled.connect(self.set_path_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # FS criteria # def clear_fs_error(self): self.clear_criteria_error(self.fs, "Match the filesystem type.") def set_fs(self): try: self.query.fs = self.fs.text() except Exception as ex: self.log.error("Filesystem type error: {0}".format(ex)) self.set_criteria_error(self.fs, ex) def set_fs_regex(self, state): self.log.debug("Setting fs_regex {0}".format(state)) self.query.fs_regex = state self.clear_fs_error() self.set_fs() # # Path criteria # def clear_path_error(self): self.clear_criteria_error(self.path, "Match the path.") def set_path(self): try: self.query.path = self.path.text() except Exception as ex: self.log.error("Path error: {0}".format(ex)) self.set_criteria_error(self.path, ex) def set_path_regex(self, state): self.log.debug("Setting path_regex {0}".format(state)) self.query.path_regex = state self.clear_path_error() self.set_path() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "path_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["fs", "path", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "path_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["fs", "path", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} genfscon(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/genfsconquery.ui000066400000000000000000000561751314142262400216010ustar00rootroot00000000000000 GenfsconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Genfscon Statements Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised Filesystem Type Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Path Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 QDialogButtonBox::Apply SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander fs fs_regex path path_regex user user_regex role role_regex type_ type_regex range_ range_exact range_subset range_overlap range_superset results_frame table_results notes raw_results criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/infoflow.py000066400000000000000000000473761314142262400205520ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from collections import defaultdict from PyQt5.QtCore import pyqtSignal, Qt, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog, \ QTreeWidgetItem from setools import InfoFlowAnalysis from setools.exception import UnmappedClass, UnmappedPermission from ..logtosignal import LogHandlerToSignal from .analysistab import AnalysisTab from .exception import TabFieldError from .excludetypes import ExcludeTypes from .permmapedit import PermissionMapEditor from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \ save_checkboxes, save_spinboxes, save_lineedits, save_textedits class InfoFlowAnalysisTab(AnalysisTab): """An information flow analysis tab.""" @property def perm_map(self): return self.query.perm_map @perm_map.setter def perm_map(self, pmap): # copy permission map to keep enabled/disabled # settings private to this map. perm_map = copy.deepcopy(pmap) # transfer enabled/disabled settings from # current permission map, to the new map for classname in self.query.perm_map.classes(): for mapping in self.query.perm_map.perms(classname): try: perm_map.mapping(classname, mapping.perm).enabled = mapping.enabled except (UnmappedClass, UnmappedPermission): pass # apply updated permission map self.query.perm_map = perm_map def __init__(self, parent, policy, perm_map): super(InfoFlowAnalysisTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = InfoFlowAnalysis(policy, perm_map) self.query.source = None self.query.target = None self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.infoflow").removeHandler(self.handler) def setupUi(self): self.log.debug("Initializing UI.") self.load_ui("apol/infoflow.ui") # set up error message for missing perm map self.error_msg = QMessageBox(self) self.error_msg.setStandardButtons(QMessageBox.Ok) # set up perm map editor self.permmap_editor = PermissionMapEditor(self, False) # set up source/target autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.source.setCompleter(self.type_completion) self.target.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() # set up processing thread self.thread = ResultsUpdater(self.query) self.thread.raw_line.connect(self.raw_results.appendPlainText) self.thread.finished.connect(self.update_complete) self.thread.flows.connect(self.reset_browser) # set up browser thread self.browser_thread = BrowserUpdater(self.query) self.browser_thread.flows.connect(self.add_browser_children) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.setCancelButton(None) self.busy.reset() # update busy dialog from infoflow INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.infoflow").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.max_path_length.setEnabled(self.all_paths.isChecked()) self.source.setEnabled(not self.flows_in.isChecked()) self.target.setEnabled(not self.flows_out.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) self.browser_tab.setEnabled(self.flows_in.isChecked() or self.flows_out.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.all_paths.toggled.connect(self.all_paths_toggled) self.flows_in.toggled.connect(self.flows_in_toggled) self.flows_out.toggled.connect(self.flows_out_toggled) self.min_perm_weight.valueChanged.connect(self.set_min_weight) self.exclude_types.clicked.connect(self.choose_excluded_types) self.edit_permmap.clicked.connect(self.open_permmap_editor) self.browser.currentItemChanged.connect(self.browser_item_selected) # # Analysis mode # def all_paths_toggled(self, value): self.clear_source_error() self.clear_target_error() self.max_path_length.setEnabled(value) def flows_in_toggled(self, value): self.clear_source_error() self.clear_target_error() self.source.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) def flows_out_toggled(self, value): self.clear_source_error() self.clear_target_error() self.target.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "The source type of the analysis.") def set_source(self): try: # look up the type here, so invalid types can be caught immediately text = self.source.text() if text: self.query.source = self.policy.lookup_type(text) else: self.query.source = None except Exception as ex: self.log.error("Source type error: {0}".format(str(ex))) self.set_criteria_error(self.source, ex) # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "The target type of the analysis.") def set_target(self): try: # look up the type here, so invalid types can be caught immediately text = self.target.text() if text: self.query.target = self.policy.lookup_type(text) else: self.query.target = None except Exception as ex: self.log.error("Target type error: {0}".format(str(ex))) self.set_criteria_error(self.target, ex) # # Options # def set_min_weight(self, value): self.query.min_weight = value def choose_excluded_types(self): chooser = ExcludeTypes(self, self.policy) chooser.show() def open_permmap_editor(self): self.permmap_editor.show(self.perm_map) def apply_permmap(self, pmap): # used only by permission map editor self.query.perm_map = pmap # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out"]) save_lineedits(self, settings, ["source", "target"]) save_spinboxes(self, settings, ["max_path_length", "limit_paths", "min_perm_weight"]) save_textedits(self, settings, ["notes"]) settings["exclude"] = [str(t) for t in self.query.exclude] settings["exclude_perms"] = defaultdict(list) for mapping in self.perm_map: if not mapping.enabled: settings["exclude_perms"][mapping.class_].append(mapping.perm) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out"]) load_lineedits(self, settings, ["source", "target"]) load_spinboxes(self, settings, ["max_path_length", "limit_paths", "min_perm_weight"]) load_textedits(self, settings, ["notes"]) try: self.query.exclude = settings["exclude"] except KeyError: self.log.warning("Excluded types criteria missing from settings file.") if "exclude_perms" not in settings: self.log.warning("Excluded permissions missing from settings file.") else: for mapping in self.perm_map: # iterate over the map so that any permission # not in the setting file's exclude list is enabled. try: mapping.enabled = mapping.perm not in settings["exclude_perms"][mapping.class_] except KeyError: mapping.enabled = True # # Infoflow browser # def _new_browser_item(self, type_, parent, rules=None, children=None): # build main item item = QTreeWidgetItem(parent if parent else self.browser) item.setText(0, str(type_)) item.type_ = type_ item.children = children if children else [] item.rules = rules if rules else [] item.child_populated = children is not None # add child items for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.setExpanded(children is not None) self.log.debug("Built item for {0} with {1} children and {2} rules".format( type_, len(item.children), len(item.rules))) return item def reset_browser(self, root_type, out, children): self.log.debug("Resetting browser.") # clear results self.browser.clear() self.browser_details.clear() # save browser details independent # from main analysis UI settings self.browser_root_type = root_type self.browser_mode = out root = self._new_browser_item(self.browser_root_type, self.browser, children=children) self.browser.insertTopLevelItem(0, root) def browser_item_selected(self, current, previous): if not current: # browser is being reset return self.log.debug("{0} selected in browser.".format(current.type_)) self.browser_details.clear() try: parent_type = current.parent().type_ except AttributeError: # should only hit his on the root item pass else: self.browser_details.appendPlainText("Information flows {0} {1} {2}\n".format( current.parent().type_, "->" if self.browser_mode else "<-", current.type_)) for rule in current.rules: self.browser_details.appendPlainText(rule) self.browser_details.moveCursor(QTextCursor.Start) if not current.child_populated: self.busy.setLabelText("Gathering additional browser details for {0}...".format( current.type_)) self.busy.show() self.browser_thread.out = self.browser_mode self.browser_thread.type_ = current.type_ self.browser_thread.start() def add_browser_children(self, children): item = self.browser.currentItem() item.children = children self.log.debug("Adding children for {0}".format(item.type_)) for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.child_populated = True self.busy.reset() # # Results runner # def run(self, button): # right now there is only one button. fail = False if self.source.isEnabled() and not self.query.source: self.set_criteria_error(self.source, "A source type is required") fail = True if self.target.isEnabled() and not self.query.target: self.set_criteria_error(self.target, "A target type is required.") fail = True if not self.perm_map: self.log.critical("A permission map is required to begin the analysis.") self.error_msg.critical(self, "No permission map available.", "Please load a permission map to begin the analysis.") fail = True if fail: return for mode in [self.all_paths, self.all_shortest_paths, self.flows_in, self.flows_out]: if mode.isChecked(): break self.query.mode = mode.objectName() self.query.max_path_len = self.max_path_length.value() self.query.limit = self.limit_paths.value() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self): if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) if self.flows_in.isChecked() or self.flows_out.isChecked(): # move to browser tab for flows in/out self.results_frame.setCurrentIndex(1) else: self.results_frame.setCurrentIndex(0) self.busy.reset() class ResultsUpdater(QThread): """ Thread for processing queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: raw_line A string to be appended to the raw results. flows (str, bool, list) Initial information for populating the flows browser. """ raw_line = pyqtSignal(str) flows = pyqtSignal(str, bool, list) def __init__(self, query): super(ResultsUpdater, self).__init__() self.query = query self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): """Run the query and update results.""" assert self.query.limit, "Code doesn't currently handle unlimited (limit=0) paths." self.out = self.query.mode == "flows_out" if self.query.mode == "all_paths": self.transitive(self.query.all_paths(self.query.source, self.query.target, self.query.max_path_len)) elif self.query.mode == "all_shortest_paths": self.transitive(self.query.all_shortest_paths(self.query.source, self.query.target)) elif self.query.mode == "flows_out": self.direct(self.query.infoflows(self.query.source, out=self.out)) else: # flows_in self.direct(self.query.infoflows(self.query.target, out=self.out)) def transitive(self, paths): pathnum = 0 for pathnum, path in enumerate(paths, start=1): self.raw_line.emit("Flow {0}:".format(pathnum)) for stepnum, step in enumerate(path, start=1): self.raw_line.emit(" Step {0}: {1} -> {2}".format(stepnum, step.source, step.target)) for rule in sorted(step.rules): self.raw_line.emit(" {0}".format(rule)) self.raw_line.emit("") if QThread.currentThread().isInterruptionRequested() or (pathnum >= self.query.limit): break else: QThread.yieldCurrentThread() self.raw_line.emit("") self.raw_line.emit("{0} information flow path(s) found.\n".format(pathnum)) self.log.info("{0} information flow path(s) found.".format(pathnum)) def direct(self, flows): flownum = 0 child_types = [] for flownum, flow in enumerate(flows, start=1): self.raw_line.emit("Flow {0}: {1} -> {2}".format(flownum, flow.source, flow.target)) for rule in sorted(flow.rules): self.raw_line.emit(" {0}".format(rule)) self.raw_line.emit("") # Generate results for flow browser if self.out: child_types.append((flow.target, sorted(str(r) for r in flow.rules))) else: child_types.append((flow.source, sorted(str(r) for r in flow.rules))) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} information flow(s) found.\n".format(flownum)) self.log.info("{0} information flow(s) found.".format(flownum)) # Update browser: root_type = self.query.source if self.out else self.query.target self.flows.emit(str(root_type), self.out, sorted(child_types)) class BrowserUpdater(QThread): """ Thread for processing additional analysis for the browser. Parameters: query The query object model The model for the results Qt signals: flows A list of child types to render in the infoflows browser. """ flows = pyqtSignal(list) def __init__(self, query): super(BrowserUpdater, self).__init__() self.query = query self.type_ = None self.out = None self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): flownum = 0 child_types = [] for flownum, flow in enumerate(self.query.infoflows(self.type_, out=self.out), start=1): # Generate results for flow browser if self.out: child_types.append((flow.target, sorted(str(r) for r in flow.rules))) else: child_types.append((flow.source, sorted(str(r) for r in flow.rules))) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.log.debug("{0} additional information flow(s) found.".format(flownum)) # Update browser: self.flows.emit(sorted(child_types)) setools-4.1.1/setoolsgui/apol/infoflow.ui000066400000000000000000000473221314142262400205260ustar00rootroot00000000000000 InfoflowAnalysisTab 0 0 774 846 0 0 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 Options 3 3 6 6 6 6 Minimum permission weight: 1 10 Limit results: 1 1000 20 Excluded Types: Edit... Edit... Excluded Permissions: 16777215 100 Target Type 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 16777215 100 Source Type 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 QDialogButtonBox::Apply Analysis Mode 6 6 6 6 3 The limit for path length. steps 1 3 All information flows into the target type will be shown. Flows into the target type All paths from the source type to the target type, up to the specified maximum length, will be shown. All paths up to All shortest paths from the source type to the target type will be shown. Shortest paths true All information flows out of the source type will be shown. Flows out of the source type source_criteria target_criteria buttonBox groupBox groupBox_2 0 0 16777215 20 12 75 true Information Flow Analysis Qt::Horizontal 40 20 Show: 0 1 0 0 0 Raw Results 3 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true true Browser Qt::Horizontal 1 0 Type 4 0 Monospace Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 0 0 80 Optionally enter notes here about the query. Enter notes here. SEToolsTreeWidget QTreeWidget
setoolsgui/treeview.h
criteria_expander notes_expander source target all_shortest_paths all_paths max_path_length flows_out flows_in min_perm_weight limit_paths exclude_types results_frame raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 19 386 174 notes_expander toggled(bool) notes setVisible(bool) 732 19 386 708
setools-4.1.1/setoolsgui/apol/initsidquery.py000066400000000000000000000267111314142262400214460ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import InitialSIDQuery from ..logtosignal import LogHandlerToSignal from ..initsidmodel import InitialSIDTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class InitialSIDQueryTab(AnalysisTab): """An initial SID query.""" def __init__(self, parent, policy, perm_map): super(InitialSIDQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = InitialSIDQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.initsidquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/initsidquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = InitialSIDTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.initsidquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} initial SID statment(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/initsidquery.ui000066400000000000000000000531041314142262400214270ustar00rootroot00000000000000 InitialSIDQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Initial SID Statements 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Name Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox name_criteria Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander name name_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/mainwindow.py000066400000000000000000000652611314142262400210740ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import sys import stat import logging import json from errno import ENOENT import pkg_resources from PyQt5.QtCore import pyqtSlot, Qt, QProcess from PyQt5.QtWidgets import QApplication, QFileDialog, QLineEdit, QMainWindow, QMessageBox from setools import __version__, PermissionMap, SELinuxPolicy from ..widget import SEToolsWidget from ..logtosignal import LogHandlerToSignal from .chooseanalysis import ChooseAnalysis, tab_map from .exception import TabFieldError from .permmapedit import PermissionMapEditor from .summary import SummaryTab class ApolMainWindow(SEToolsWidget, QMainWindow): def __init__(self, filename): super(ApolMainWindow, self).__init__() self.log = logging.getLogger(__name__) self._permmap = None self._policy = None self.setupUi() self.load_permmap() if filename: self.load_policy(filename) if self._policy: self.create_new_analysis("Summary", SummaryTab) self.update_window_title() self.toggle_workspace_actions() def setupUi(self): self.load_ui("apol/apol.ui") self.tab_counter = 0 # set up analysis menu self.chooser = ChooseAnalysis(self) # set up error message dialog self.error_msg = QMessageBox(self) self.error_msg.setStandardButtons(QMessageBox.Ok) # set up permission map editor self.permmap_editor = PermissionMapEditor(self, True) # set up tab name editor self.tab_editor = QLineEdit(self.AnalysisTabs) self.tab_editor.setWindowFlags(Qt.Popup) # configure tab bar context menu tabBar = self.AnalysisTabs.tabBar() tabBar.addAction(self.rename_tab_action) tabBar.addAction(self.close_tab_action) tabBar.setContextMenuPolicy(Qt.ActionsContextMenu) # capture INFO and higher Python messages from setools lib for status bar handler = LogHandlerToSignal() handler.message.connect(self.statusbar.showMessage) logging.getLogger("setools").addHandler(handler) logging.getLogger("setoolsgui").addHandler(handler) # set up help browser process self.help_process = QProcess() # connect signals self.open_policy.triggered.connect(self.select_policy) self.close_policy_action.triggered.connect(self.close_policy) self.open_permmap.triggered.connect(self.select_permmap) self.new_analysis.triggered.connect(self.choose_analysis) self.AnalysisTabs.currentChanged.connect(self.toggle_workspace_actions) self.AnalysisTabs.tabCloseRequested.connect(self.close_tab) self.AnalysisTabs.tabBarDoubleClicked.connect(self.tab_name_editor) self.tab_editor.editingFinished.connect(self.rename_tab) self.rename_tab_action.triggered.connect(self.rename_active_tab) self.close_tab_action.triggered.connect(self.close_active_tab) self.new_from_settings_action.triggered.connect(self.new_analysis_from_config) self.load_settings_action.triggered.connect(self.load_settings) self.save_settings_action.triggered.connect(self.save_settings) self.load_workspace_action.triggered.connect(self.load_workspace) self.save_workspace_action.triggered.connect(self.save_workspace) self.copy_action.triggered.connect(self.copy) self.cut_action.triggered.connect(self.cut) self.paste_action.triggered.connect(self.paste) self.edit_permmap_action.triggered.connect(self.edit_permmap) self.save_permmap_action.triggered.connect(self.save_permmap) self.about_apol_action.triggered.connect(self.about_apol) self.apol_help_action.triggered.connect(self.apol_help) self.show() def update_window_title(self): if self._policy: self.setWindowTitle("{0} - apol".format(self._policy)) else: self.setWindowTitle("apol") # # Policy handling # def select_policy(self): old_policy = self._policy if old_policy and self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Loading a policy will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return filename = QFileDialog.getOpenFileName(self, "Open policy file", ".", "SELinux Policies (policy.* sepolicy);;" "All Files (*)")[0] if filename: self.load_policy(filename) if self._policy != old_policy: # policy loading succeeded, clear any # existing tabs self.AnalysisTabs.clear() self.create_new_analysis("Summary", SummaryTab) def load_policy(self, filename): try: self._policy = SELinuxPolicy(filename) except Exception as ex: self.log.critical("Failed to load policy \"{0}\"".format(filename)) self.error_msg.critical(self, "Policy loading error", str(ex)) else: self.update_window_title() self.toggle_workspace_actions() if self._permmap: self._permmap.map_policy(self._policy) self.apply_permmap() def close_policy(self): if self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Loading a policy will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return self.AnalysisTabs.clear() self._policy = None self.update_window_title() self.toggle_workspace_actions() # # Permission map handling # def select_permmap(self): filename = QFileDialog.getOpenFileName(self, "Open permission map file", ".")[0] if filename: self.load_permmap(filename) def load_permmap(self, filename=None): try: self._permmap = PermissionMap(filename) except Exception as ex: self.log.critical("Failed to load default permission map: {0}".format(ex)) self.error_msg.critical(self, "Permission map loading error", str(ex)) else: if self._policy: self._permmap.map_policy(self._policy) self.apply_permmap() def edit_permmap(self): if not self._permmap: self.error_msg.critical(self, "No open permission map", "Cannot edit permission map. Please open a map first.") self.select_permmap() # in case user cancels out of # choosing a permmap, recheck if self._permmap: self.permmap_editor.show(self._permmap) def apply_permmap(self, perm_map=None): if perm_map: self._permmap = perm_map for index in range(self.AnalysisTabs.count()): tab = self.AnalysisTabs.widget(index) self.log.debug("Updating permmap in tab {0} ({1}: \"{2}\")".format( index, tab, tab.objectName())) tab.perm_map = self._permmap def save_permmap(self): path = str(self._permmap) if self._permmap else "perm_map" filename = QFileDialog.getSaveFileName(self, "Save permission map file", path)[0] if filename: try: self._permmap.save(filename) except Exception as ex: self.log.critical("Failed to save permission map: {0}".format(ex)) self.error_msg.critical(self, "Permission map saving error", str(ex)) # # Analysis tab handling # def choose_analysis(self): if not self._policy: self.error_msg.critical(self, "No open policy", "Cannot start a new analysis. Please open a policy first.") self.select_policy() if self._policy: # this check of self._policy is here in case someone # tries to start an analysis with no policy open, but then # cancels out of the policy file chooser or there is an # error opening the policy file. self.chooser.show(self._policy.mls) def create_new_analysis(self, tabtitle, tabclass): self.tab_counter += 1 counted_name = "{0}: {1}".format(self.tab_counter, tabtitle) newanalysis = tabclass(self, self._policy, self._permmap) newanalysis.setAttribute(Qt.WA_DeleteOnClose) newanalysis.setObjectName(counted_name) index = self.AnalysisTabs.addTab(newanalysis, counted_name) self.AnalysisTabs.setTabToolTip(index, tabtitle) self.AnalysisTabs.setCurrentIndex(index) return index def tab_name_editor(self, index): if index >= 0: tab_area = self.AnalysisTabs.tabBar().tabRect(index) self.tab_editor.move(self.AnalysisTabs.mapToGlobal(tab_area.topLeft())) self.tab_editor.setText(self.AnalysisTabs.tabText(index)) self.tab_editor.selectAll() self.tab_editor.show() self.tab_editor.setFocus() def close_active_tab(self): """Close the active tab. This is called from the context menu.""" index = self.AnalysisTabs.currentIndex() if index >= 0: self.close_tab(index) def rename_active_tab(self): """Rename the active tab.""" index = self.AnalysisTabs.currentIndex() if index >= 0: self.tab_name_editor(index) def close_tab(self, index): """Close a tab specified by index.""" widget = self.AnalysisTabs.widget(index) widget.close() self.AnalysisTabs.removeTab(index) def rename_tab(self): # this should never be negative since the editor is modal index = self.AnalysisTabs.currentIndex() tab = self.AnalysisTabs.widget(index) title = self.tab_editor.text() self.tab_editor.hide() self.AnalysisTabs.setTabText(index, title) tab.setObjectName(title) # # Workspace actions # def toggle_workspace_actions(self, index=-1): """ Enable or disable workspace actions depending on how many tabs are open and if a policy is open. This is a slot for the QTabWidget.currentChanged() signal, though index is ignored. """ open_tabs = self.AnalysisTabs.count() > 0 open_policy = self._policy is not None self.log.debug("{0} actions requiring an open policy.". format("Enabling" if open_policy else "Disabling")) self.log.debug("{0} actions requiring open tabs.". format("Enabling" if open_tabs else "Disabling")) self.save_settings_action.setEnabled(open_tabs) self.save_workspace_action.setEnabled(open_tabs) self.new_analysis.setEnabled(open_policy) self.new_from_settings_action.setEnabled(open_policy) self.load_settings_action.setEnabled(open_tabs) def _get_settings(self, index=None): """Return a dictionary with the settings of the tab at the specified index.""" if index is None: index = self.AnalysisTabs.currentIndex() assert index >= 0, "Tab index is negative in _get_settings. This is an SETools bug." tab = self.AnalysisTabs.widget(index) settings = tab.save() # add the tab info to the settings. settings["__title__"] = self.AnalysisTabs.tabText(index) settings["__tab__"] = type(tab).__name__ return settings def _put_settings(self, settings, index=None): """Load the settings into the specified tab.""" if index is None: index = self.AnalysisTabs.currentIndex() assert index >= 0, "Tab index is negative in _put_settings. This is an SETools bug." tab = self.AnalysisTabs.widget(index) if settings["__tab__"] != type(tab).__name__: raise TypeError("The current tab ({0}) does not match the tab in the settings file " "({1}).".format(type(tab).__name__, settings["__tab__"])) try: self.AnalysisTabs.setTabText(index, str(settings["__title__"])) except KeyError: self.log.warning("Settings file does not have a title setting.") tab.load(settings) def load_settings(self, new=False): filename = QFileDialog.getOpenFileName(self, "Open settings file", ".", "Apol Tab Settings File (*.apolt);;" "All Files (*)")[0] if not filename: return try: with open(filename, "r") as fd: settings = json.load(fd) except ValueError as ex: self.log.critical("Invalid settings file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load settings", "Invalid settings file: \"{0}\"".format(filename)) return except (IOError, OSError) as ex: self.log.critical("Unable to load settings file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to load settings", "Failed to load \"{0.filename}\": {0.strerror}".format(ex)) return except Exception as ex: self.log.critical("Unable to load settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load settings", str(ex)) return self.log.info("Loading analysis settings from \"{0}\"".format(filename)) if new: try: tabclass = tab_map[settings["__tab__"]] except KeyError: self.log.critical("Missing analysis type in \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load settings", "The type of analysis is missing in the settings file.") return # The tab title will be set by _put_settings. index = self.create_new_analysis("Tab", tabclass) else: index = None try: self._put_settings(settings, index) except Exception as ex: self.log.critical("Error loading settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load settings", "Error loading settings file \"{0}\":\n\n{1}". format(filename, ex)) else: self.log.info("Successfully loaded analysis settings from \"{0}\"".format(filename)) def new_analysis_from_config(self): self.load_settings(new=True) def save_settings(self): try: settings = self._get_settings() except TabFieldError as ex: self.log.critical("Errors in the query prevent saving the settings. {0}".format(ex)) self.error_msg.critical(self, "Unable to save settings", "Please resolve errors in the tab before saving the settings." ) return filename = QFileDialog.getSaveFileName(self, "Save analysis tab settings", "analysis.apolt", "Apol Tab Settings File (*.apolt);;" "All Files (*)")[0] if not filename: return try: with open(filename, "w") as fd: json.dump(settings, fd, indent=1) except (IOError, OSError) as ex: self.log.critical("Unable to save settings file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to save settings", "Failed to save \"{0.filename}\": {0.strerror}".format(ex)) except Exception as ex: self.log.critical("Unable to save settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to save settings", str(ex)) else: self.log.info("Successfully saved settings file \"{0}\"".format(filename)) def load_workspace(self): # 1. if number of tabs > 0, check if we really want to do this if self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Loading a workspace will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return # 2. try to load the workspace file, if we fail, bail filename = QFileDialog.getOpenFileName(self, "Open workspace file", ".", "Apol Workspace Files (*.apolw);;" "All Files (*)")[0] if not filename: return try: with open(filename, "r") as fd: workspace = json.load(fd) except ValueError as ex: self.log.critical("Invalid workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load workspace", "Invalid workspace file: \"{0}\"".format(filename)) return except (IOError, OSError) as ex: self.log.critical("Unable to load workspace file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to load workspace", "Failed to load \"{0.filename}\": {0.strerror}".format(ex)) return except Exception as ex: self.log.critical("Unable to load workspace file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load workspace", str(ex)) return # 3. close all tabs. Explicitly do this to avoid the question # about closing the policy with tabs open. self.AnalysisTabs.clear() # 4. close policy self.close_policy() # 5. try to open the specified policy, if we fail, bail. Note: # handling exceptions from the policy load is done inside # the load_policy function, so only the KeyError needs to be caught here try: self.load_policy(workspace["__policy__"]) except KeyError: self.log.critical("Missing policy in workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Missing policy in workspace file \"{0}\"". format(filename)) if self._policy is None: self.log.critical("The policy could not be loaded in workspace file \"{0}\"". format(filename)) self.error_msg.critical(self, "The policy could not be loaded in workspace file \"{0}\"" ". Aborting workspace load.".format(filename)) return # 6. try to open the specified perm map, if we fail, # tell the user we will continue with the default map; load the default map # Note: handling exceptions from the map load is done inside # the load_permmap function, so only the KeyError needs to be caught here try: self.load_permmap(workspace["__permmap__"]) except KeyError: self.log.warning("Missing permission map in workspace file \"{0}\"".format(filename)) self.error_msg.warning(self, "Missing permission map setting.", "Missing permission map in workspace file \"{0}\"". format(filename)) if self._permmap is None: self.error_msg.information(self, "Loading default permission map.", "The default permisison map will be loaded.") self.load_permmap() # 7. try to open all tabs and apply settings. Record any errors try: tab_list = list(workspace["__tabs__"]) except KeyError: self.log.critical("Missing tab list in workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load workspace", "The workspace file is missing the tab list. Aborting.") return except TypeError: self.log.critical("Invalid tab list in workspace file.") self.error_msg.critical(self, "Failed to load workspace", "The tab count is invalid. Aborting.") return loading_errors = [] for i, settings in enumerate(tab_list): try: tabclass = tab_map[settings["__tab__"]] except KeyError: error_str = "Missing analysis type for tab {0}. Skipping this tab.".format(i) self.log.error(error_str) loading_errors.append(error_str) continue # The tab title will be set by _put_settings. index = self.create_new_analysis("Tab", tabclass) try: self._put_settings(settings, index) except Exception as ex: error_str = "Error loading settings for tab {0}: {1}".format(i, ex) self.log.error(error_str) loading_errors.append(error_str) self.log.info("Completed loading workspace from \"{0}\"".format(filename)) # 8. if there are any errors, open a dialog with the # complete list of tab errors if loading_errors: self.error_msg.warning(self, "Errors while loading workspace:", "There were errors while loading the workspace:\n\n{0}". format("\n\n".join(loading_errors))) def save_workspace(self): workspace = {} save_errors = [] workspace["__policy__"] = os.path.abspath(str(self._policy)) workspace["__permmap__"] = os.path.abspath(str(self._permmap)) workspace["__tabs__"] = [] for index in range(self.AnalysisTabs.count()): tab = self.AnalysisTabs.widget(index) try: settings = tab.save() except TabFieldError as ex: tab_name = self.AnalysisTabs.tabText(index) save_errors.append(tab_name) self.log.error("Error: tab \"{0}\": {1}".format(tab_name, str(ex))) else: # add the tab info to the settings. settings["__title__"] = self.AnalysisTabs.tabText(index) settings["__tab__"] = type(tab).__name__ workspace["__tabs__"].append(settings) if save_errors: self.log.critical("Errors in tabs prevent saving the workspace.") self.error_msg.critical(self, "Unable to save workspace", "Please resolve errors in the following tabs before saving the" " workspace:\n\n{0}".format("\n".join(save_errors))) return filename = QFileDialog.getSaveFileName(self, "Save analysis workspace", "workspace.apolw", "Apol Workspace Files (*.apolw);;" "All Files (*)")[0] if not filename: return with open(filename, "w") as fd: json.dump(workspace, fd, indent=1) # # Edit actions # def copy(self): """Copy text from the currently-focused widget.""" try: QApplication.instance().focusWidget().copy() except AttributeError: pass def cut(self): """Cut text from the currently-focused widget.""" try: QApplication.instance().focusWidget().cut() except AttributeError: pass def paste(self): """Paste text into the currently-focused widget.""" try: QApplication.instance().focusWidget().paste() except AttributeError: pass # # Help actions # def about_apol(self): QMessageBox.about(self, "About Apol", "Version {0}
" "Apol is a graphical SELinux policy analysis tool and part of " "" "SETools.

" "Copyright (C) 2015-2016, Tresys Technology.".format(__version__)) def apol_help(self): """Open the main help window.""" if self.help_process.state() != QProcess.NotRunning: return distro = pkg_resources.get_distribution("setools") helpfile = "{0}/setoolsgui/apol/apol.qhc".format(distro.location) self.log.debug("Starting assistant with help file {0}".format(helpfile)) self.help_process.start("assistant", ["-collectionFile", helpfile, "-showUrl", "qthelp://com.github.tresystechnology.setools/doc/index.html", "-show", "contents", "-enableRemoteControl"]) @pyqtSlot(str) def set_help(self, location): """Set the help window to the specified document.""" if self.help_process.state() == QProcess.NotStarted: self.apol_help() if not self.help_process.waitForStarted(): self.log.warning("Timed out waiting for Qt assistant to start.") return elif self.help_process.state() == QProcess.Starting: if not self.help_process.waitForStarted(): self.log.warning("Timed out waiting for Qt assistant to start.") return self.help_process.write("setSource qthelp://com.github.tresystechnology.setools/doc/{0}\n". format(location)) setools-4.1.1/setoolsgui/apol/mlsrulequery.py000066400000000000000000000244461314142262400214710ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import MLSRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsrulemodel import MLSRuleTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class MLSRuleQueryTab(AnalysisTab): """An MLS rule query.""" def __init__(self, parent, policy, perm_map): super(MLSRuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = MLSRuleQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.mlsrulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/mlsrulequery.ui") # set up source/target autocompletion typeattr_completion_list = [str(t) for t in self.policy.types()] typeattr_completion_list.extend(str(a) for a in self.policy.typeattributes()) typeattr_completer_model = QStringListModel(self) typeattr_completer_model.setStringList(sorted(typeattr_completion_list)) self.typeattr_completion = QCompleter() self.typeattr_completion.setModel(typeattr_completer_model) self.source.setCompleter(self.typeattr_completion) self.target.setCompleter(self.typeattr_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # set up results self.table_results_model = MLSRuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.mlsrulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.default_range.textEdited.connect(self.clear_default_error) self.default_range.editingFinished.connect(self.set_default_range) # # Ruletype criteria # def _set_ruletypes(self, value): self.range_transition.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source type/attribute of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source type/attribute error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target type/attribute of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/attribute error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_range, "Match the default type the rule.") def set_default_range(self): try: self.query.default = self.default_range.text() except Exception as ex: self.log.error("Default range error: {0}".format(ex)) self.set_criteria_error(self.default_range, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "range_transition", "source_indirect", "source_regex", "target_indirect", "target_regex"]) save_lineedits(self, settings, ["source", "target", "default_range"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "range_transition", "source_indirect", "source_regex", "target_indirect", "target_regex"]) load_lineedits(self, settings, ["source", "target", "default_range"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.ruletype = ['range_transition'] self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} MLS rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/mlsrulequery.ui000066400000000000000000000575361314142262400214640ustar00rootroot00000000000000 MLSRuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Qt::Horizontal 40 20 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 0 16777215 20 12 75 true Multi-Level Security (MLS) Rule Query 0 1 0 80 Optionally enter notes here about the query. Enter notes here. 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Type/Attribute 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 false Select All Qt::Horizontal 40 20 false Clear false false Range_transition true 16777215 100 Source Type/Attribute 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 Use regular expressions to match the source type/attribute. Regex If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection QDialogButtonBox::Apply Default Range 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 ruletype_criteria source_criteria target_criteria class_criteria buttonBox default_criteria SEToolsTableView QTableView

setoolsgui/tableview.h
criteria_expander notes_expander range_transition clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class default_range results_frame table_results raw_results notes clear_class clicked() tclass clearSelection() 299 312 147 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 222 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756 setools-4.1.1/setoolsgui/apol/netifconquery.py000066400000000000000000000267101314142262400216070ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import NetifconQuery from ..logtosignal import LogHandlerToSignal from ..netifconmodel import NetifconTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class NetifconQueryTab(AnalysisTab): """A netifcon query.""" def __init__(self, parent, policy, perm_map): super(NetifconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = NetifconQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.netifconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/netifconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = NetifconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.netifconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the device name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Device name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} netifcon statment(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/netifconquery.ui000066400000000000000000000531341314142262400215740ustar00rootroot00000000000000 NetifconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Netifcon Statements 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Device Context Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 QDialogButtonBox::Apply 16777215 100 Device Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Device Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Device Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Device Name Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox name_criteria Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander name name_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/nodeconquery.py000066400000000000000000000305451314142262400214300ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import NodeconQuery, NodeconIPVersion from ..logtosignal import LogHandlerToSignal from ..nodeconmodel import NodeconTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \ save_checkboxes, save_lineedits, save_textedits, save_comboboxes class NodeconQueryTab(AnalysisTab): """An nodecon query.""" def __init__(self, parent, policy, perm_map): super(NodeconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = NodeconQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.nodeconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/nodeconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup IP version # item 0 is empty string (in the .ui file) self.ip_version.insertItem(1, "IPv4", NodeconIPVersion.ipv4) self.ip_version.insertItem(2, "IPv6", NodeconIPVersion.ipv6) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_network_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = NodeconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.nodeconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Network criteria is available only on Python 3.3+ if sys.version_info < (3, 3): self.network_criteria.setEnabled(False) self.network_criteria.setToolTip("This feature requires Python 3.3 or newer.") self.network.setToolTip("This feature requires Python 3.3 or newer.") self.network_exact.setToolTip("This feature requires Python 3.3 or newer.") self.network_overlap.setToolTip("This feature requires Python 3.3 or newer.") # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.network.textEdited.connect(self.clear_network_error) self.network.editingFinished.connect(self.set_network) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Network criteria # def clear_network_error(self): self.clear_criteria_error(self.network, "Match the network.") def set_network(self): try: self.query.network = self.network.text() except Exception as ex: self.log.error("Network error: {0}".format(ex)) self.set_criteria_error(self.network, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "network_exact", "network_overlap", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["network", "user", "role", "type_", "range_"]) save_comboboxes(self, settings, ["ip_version"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "network_exact", "network_overlap", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["network", "user", "role", "type_", "range_"]) load_comboboxes(self, settings, ["ip_version"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.network_overlap = self.network_overlap.isChecked() self.query.ip_version = self.ip_version.currentData(Qt.UserRole) self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} nodecon statment(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/nodeconquery.ui000066400000000000000000000564601314142262400214210ustar00rootroot00000000000000 NodeconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 770 842 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Nodecon Statements Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Network 0 0 150 0 e.g. 192.168.1.0/24 Match the network if the criteria overlaps the nodecon's network range. Overlap true Match the network if the criteria is equal to the nodecon's network range. Equal false Qt::Horizontal 40 20 IP Version Qt::Horizontal 40 20 Match the IP version of the nodecon. role_criteria type_criteria user_critera range_criteria buttonBox ip_version_criteria network_criteria SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander network network_exact network_overlap ip_version user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/objclassquery.py000066400000000000000000000212011314142262400215700ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import ObjClassQuery from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..objclassmodel import ObjClassTableModel, class_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class ObjClassQueryTab(AnalysisTab): """ObjClass browser and query tab.""" def __init__(self, parent, policy, perm_map): super(ObjClassQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = ObjClassQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.objclassquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/objclassquery.ui") # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(c for c in self.policy.classes()) self.classes.setModel(self.class_model) # populate commons list self.common_model = SEToolsListModel(self) self.common_model.item_list = sorted(c for c in self.policy.commons()) self.common.setModel(self.common_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # set up results self.table_results_model = ObjClassTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.objclassquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.classes.doubleClicked.connect(self.get_detail) self.classes.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.common.selectionModel().selectionChanged.connect(self.set_common) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.buttonBox.clicked.connect(self.run) # # Class browser # def get_detail(self): # .ui is set for single item selection. index = self.classes.selectedIndexes()[0] item = self.class_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) class_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the object class name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Object class name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Common criteria # def set_common(self): for index in self.common.selectionModel().selectedIndexes(): self.query.common = self.common_model.data(index, Qt.UserRole) break else: self.query.common = None # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["common", "perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["common", "perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.perms_equal = self.perms_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} object class(es) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/objclassquery.ui000066400000000000000000000444171314142262400215730ustar00rootroot00000000000000 ObjClassQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Object Classes 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Class Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Class Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex 16777215 120 Common 6 6 6 6 3 A matching class will inherit the selected common. QAbstractItemView::NoEditTriggers Clear Permission Set 0 0 250 16777215 A matching class will have the selected permissions. QAbstractItemView::ExtendedSelection Clear A matching class will have a permission set equal to the selected permissions. Equal Qt::Horizontal 40 20 Invert Qt::Vertical 20 40 QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander classes name name_regex common clear_common perms clear_perms invert_perms perms_equal results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226 clear_perms clicked() perms clearSelection() 592 216 442 276 clear_common clicked() common clearSelection() 701 126 595 127
setools-4.1.1/setoolsgui/apol/permmap_editor.ui000066400000000000000000000070711314142262400217070ustar00rootroot00000000000000 PermissionMapEditor_ui 0 0 759 451 Dialog 11 75 true Permission Map Editor QFrame::StyledPanel QFrame::Raised Include All Permissions 250 16777215 Exclude All Permissions true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 463 331 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok classes scrollArea enable_all disable_all buttonBox accepted() PermissionMapEditor_ui accept() 248 254 157 274 buttonBox rejected() PermissionMapEditor_ui reject() 316 260 286 274 setools-4.1.1/setoolsgui/apol/permmapedit.py000066400000000000000000000203311314142262400212140ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt from PyQt5.QtGui import QPalette from PyQt5.QtWidgets import QDialog, QFrame, QWidget from ..models import SEToolsListModel from ..widget import SEToolsWidget class PermissionMapEditor(SEToolsWidget, QDialog): """ A permission map editor. This dialog has two versions, one for editing the weight/direction and another for including or excluding permissions in an analysis. Parameters: parent The parent Qt widget edit (bool) If true, the dialog will take the editor behavior. If False, the dialog will take the enable/disable permission behavior. """ class_toggle = pyqtSignal(bool) def __init__(self, parent, edit): super(PermissionMapEditor, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.edit = edit self.setupUi() def setupUi(self): self.load_ui("apol/permmap_editor.ui") # set up class list self.class_model = SEToolsListModel(self) self.classes.setModel(self.class_model) # permission widgets self.widgets = [] # set up editor mode self.enable_all.setHidden(self.edit) self.disable_all.setHidden(self.edit) # connect signals self.classes.selectionModel().selectionChanged.connect(self.class_selected) self.enable_all.clicked.connect(self.enable_all_perms) self.disable_all.clicked.connect(self.disable_all_perms) def show(self, perm_map): # keep an internal copy because the map is mutable # and this dialog may be canceled after some edits. self.perm_map = copy.deepcopy(perm_map) self.class_model.item_list = sorted(perm_map.classes()) # clear class selection and mappings # since this widget will typically # be reused. self.classes.clearSelection() self._clear_mappings() self.enable_all.setToolTip(None) self.disable_all.setToolTip(None) if self.edit: self.setWindowTitle("{0} - Permission Map Editor - apol".format(self.perm_map)) else: self.setWindowTitle("{0} - Permission Map Viewer - apol".format(self.perm_map)) super(PermissionMapEditor, self).show() def accept(self): self.parent.apply_permmap(self.perm_map) super(PermissionMapEditor, self).accept() def class_selected(self): # the .ui is set to 1 selection for index in self.classes.selectionModel().selectedIndexes(): class_name = self.class_model.data(index, Qt.DisplayRole) self.log.debug("Setting class to {0}".format(class_name)) self.enable_all.setToolTip("Include all permissions in the {0} class.".format(class_name)) self.disable_all.setToolTip("Exclude all permissions in the {0} class.".format(class_name)) self._clear_mappings() # populate new mappings for perm in sorted(self.perm_map.perms(class_name)): # create permission mapping mapping = PermissionMapping(self, perm, self.edit) mapping.setAttribute(Qt.WA_DeleteOnClose) self.class_toggle.connect(mapping.enabled.setChecked) self.perm_mappings.addWidget(mapping) self.widgets.append(mapping) # add horizonal line line = QFrame(self) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.perm_mappings.addWidget(line) self.widgets.append(line) def enable_all_perms(self): self.class_toggle.emit(True) def disable_all_perms(self): self.class_toggle.emit(False) # # Internal functions # def _clear_mappings(self): # delete current mappings for mapping in self.widgets: mapping.close() # in Python3 a .clear() function was added for lists # keep this implementation for Python 2 compat del self.widgets[:] index_to_setting = ["r", "w", "b", "n"] index_to_word = ["Read", "Write", "Both", "None"] setting_to_index = {"r": 0, "w": 1, "b": 2, "n": 3} class PermissionMapping(SEToolsWidget, QWidget): """ A widget representing mapping for a particular permission. This dialog has two versions, one for editing the weight/direction and another for including or excluding permissions in an analysis. Parameters: parent The parent Qt widget edit (bool) If true, the widget will take the editor behavior. If False, the dialog will take the enable/disable permission behavior. """ def __init__(self, parent, mapping, edit): super(PermissionMapping, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.mapping = mapping self.edit = edit self.setupUi() def setupUi(self): self.load_ui("apol/permmapping.ui") self.permission.setText(str(self.mapping.perm)) self.weight.setValue(self.mapping.weight) self.enabled.setChecked(self.mapping.enabled) if self.edit: self.weight.setToolTip("Set the information flow weight of {0}".format( self.mapping.perm)) self.direction.setToolTip("Set the information flow direction of {0}".format( self.mapping.perm)) else: self.enabled.setToolTip("Include or exclude {0} from the analysis.".format( self.mapping.perm)) self.weight.setEnabled(self.edit) self.direction.setEnabled(self.edit) self.enabled.setHidden(self.edit) # setup color palettes for direction self.orig_palette = self.direction.palette() self.error_palette = self.direction.palette() self.error_palette.setColor(QPalette.Button, Qt.red) self.error_palette.setColor(QPalette.ButtonText, Qt.white) # setup direction self.direction.insertItems(0, index_to_word) if self.mapping.direction == 'u': # Temporarily add unmapped value to items self.direction.insertItem(len(index_to_word), "Unmapped") self.direction.setCurrentText("Unmapped") self.direction.setPalette(self.error_palette) self.unmapped = True else: self.direction.setCurrentIndex(setting_to_index[self.mapping.direction]) self.unmapped = False # connect signals self.direction.currentIndexChanged.connect(self.set_direction) self.weight.valueChanged.connect(self.set_weight) self.enabled.toggled.connect(self.set_enabled) def set_direction(self, value): if self.unmapped: if value == "Unmapped": return # Remove unmapped item if setting the mapping. self.direction.removeItem(len(index_to_word)) self.direction.setPalette(self.orig_palette) self.unmapped = False dir_ = index_to_setting[value] self.log.debug("Setting {0.class_}:{0.perm} direction to {1}".format(self.mapping, dir_)) self.mapping.direction = dir_ def set_weight(self, value): self.log.debug("Setting {0.class_}:{0.perm} weight to {1}".format(self.mapping, value)) self.mapping.weight = int(value) def set_enabled(self, value): self.log.debug("Setting {0.class_}:{0.perm} enabled to {1}".format(self.mapping, value)) self.mapping.enabled = value setools-4.1.1/setoolsgui/apol/permmapping.ui000066400000000000000000000022001314142262400212040ustar00rootroot00000000000000 PermMapping_ui 0 0 457 41 Form TextLabel 1 10 Include setools-4.1.1/setoolsgui/apol/portconquery.py000066400000000000000000000311201314142262400214550ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import PortconQuery, PortconProtocol from ..logtosignal import LogHandlerToSignal from ..portconmodel import PortconTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \ save_checkboxes, save_lineedits, save_textedits, save_comboboxes class PortconQueryTab(AnalysisTab): """An portcon query.""" def __init__(self, parent, policy, perm_map): super(PortconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = PortconQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.portconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/portconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_ports_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # populate protocol list. This has empty string as # the first item in the .ui file: for i, e in enumerate(PortconProtocol, start=1): self.protocol.insertItem(i, e.name.upper(), e) # set up results self.table_results_model = PortconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.portconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.ports.textEdited.connect(self.clear_ports_error) self.ports.editingFinished.connect(self.set_ports) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Ports criteria # def clear_ports_error(self): self.clear_criteria_error(self.ports, "Match the ports.") def set_ports(self): try: pending_ports = self.ports.text() if pending_ports: try: ports = [int(i) for i in pending_ports.split("-")] except ValueError: raise ValueError("Enter a port number or range, e.g. 22 or 6000-6020") if len(ports) == 2: self.query.ports = ports elif len(ports) == 1: self.query.ports = (ports[0], ports[0]) else: raise ValueError("Enter a port number or range, e.g. 22 or 6000-6020") else: self.query.ports = (0, 0) except Exception as ex: self.log.error("Ports error: {0}".format(ex)) self.set_criteria_error(self.ports, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "ports_exact", "ports_overlap", "ports_subset", "ports_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["ports", "user", "role", "type_", "range_"]) save_comboboxes(self, settings, ["protocol"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "ports_exact", "ports_overlap", "ports_subset", "ports_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["ports", "user", "role", "type_", "range_"]) load_comboboxes(self, settings, ["protocol"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.ports_overlap = self.ports_overlap.isChecked() self.query.ports_subset = self.ports_subset.isChecked() self.query.ports_superset = self.ports_superset.isChecked() self.query.protocol = self.protocol.currentData(Qt.UserRole) self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} portcon statment(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/portconquery.ui000066400000000000000000000600141314142262400214460ustar00rootroot00000000000000 PortconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 770 842 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Portcon Statements Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Port/Port Range 0 0 150 0 e.g. 80 or 6000-6010 Match the port range if the criteria is a superset to the portcon's port range. Superset Match the port range if the criteria overlaps the portcon's port range. Overlap true Match the port range if the criteria is equal to the portcon's port range. Equal false Match the port range if the criteria is a subset of the portcon's port range. Subset Qt::Horizontal 40 20 Protocol Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox protocol_criteria port_criteria SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander ports ports_exact ports_overlap ports_subset ports_superset protocol user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/queryupdater.py000066400000000000000000000037051314142262400214450ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import pyqtSignal, QObject, QThread class QueryResultsUpdater(QObject): """ Thread for processing basic queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: finished (int) The update has completed, with the number of results. raw_line (str) A string to be appended to the raw results. """ finished = pyqtSignal(int) raw_line = pyqtSignal(str) def __init__(self, query, model): super(QueryResultsUpdater, self).__init__() self.query = query self.model = model def update(self): """Run the query and update results.""" self.model.beginResetModel() results = [] counter = 0 for counter, item in enumerate(self.query.results(), start=1): results.append(item) self.raw_line.emit(str(item)) if QThread.currentThread().isInterruptionRequested(): break elif not counter % 10: # yield execution every 10 rules QThread.yieldCurrentThread() self.model.resultlist = results self.model.endResetModel() self.finished.emit(counter) setools-4.1.1/setoolsgui/apol/rbacrulequery.py000066400000000000000000000270611314142262400216010ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import RBACRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..rbacrulemodel import RBACRuleTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class RBACRuleQueryTab(AnalysisTab): """A RBAC rule query.""" def __init__(self, parent, policy, perm_map): super(RBACRuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = RBACRuleQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.rbacrulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/rbacrulequery.ui") # set up role autocompletion (source, default) role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.source.setCompleter(self.role_completion) self.default_role.setCompleter(self.role_completion) # set up role/type autocompletion (target) roletype_completion_list = [str(r) for r in self.policy.roles()] # roletype_completion_list.extend(str(a) for a in self.policy.roleattributes()) roletype_completion_list.extend(str(t) for t in self.policy.types()) roletype_completion_list.extend(str(a) for a in self.policy.typeattributes()) roletype_completer_model = QStringListModel(self) roletype_completer_model.setStringList(sorted(roletype_completion_list)) self.roletype_completion = QCompleter() self.roletype_completion.setModel(roletype_completer_model) self.target.setCompleter(self.roletype_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # set up results self.table_results_model = RBACRuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.rbacrulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.set_default_regex(self.default_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.default_role.textEdited.connect(self.clear_default_error) self.default_role.editingFinished.connect(self.set_default_role) self.default_regex.toggled.connect(self.set_default_regex) # # Ruletype criteria # def _set_ruletypes(self, value): self.allow.setChecked(value) self.role_transition.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source role of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source role error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target role/type of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/role error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_role, "Match the default role the rule.") def set_default_role(self): self.query.default_regex = self.default_regex.isChecked() try: self.query.default = self.default_role.text() except Exception as ex: self.log.error("Default role error: {0}".format(ex)) self.set_criteria_error(self.default_role, ex) def set_default_regex(self, state): self.log.debug("Setting default_regex {0}".format(state)) self.query.default_regex = state self.clear_default_error() self.set_default_role() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "role_transition", "source_indirect", "source_regex", "target_indirect", "target_regex", "default_regex"]) save_lineedits(self, settings, ["source", "target", "default_role"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "role_transition", "source_indirect", "source_regex", "target_indirect", "target_regex", "default_regex"]) load_lineedits(self, settings, ["source", "target", "default_role"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.allow, self.role_transition]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} RBAC rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/rbacrulequery.ui000066400000000000000000000607361314142262400215740ustar00rootroot00000000000000 RBACRuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show: 0 1 0 80 Optionally enter notes here about the query. Enter notes here. 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Role/Type 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Qt::Horizontal 40 20 Allow true Clear false Role_transition true 16777215 100 Source Role 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 true Use regular expressions to match the source type/attribute. Regex false If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection QDialogButtonBox::Apply Default Role 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the default type. Regex ruletype_criteria source_criteria target_criteria class_criteria buttonBox default_criteria 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Role Based Access Control (RBAC) Rule Query Show or hide the notes field (no data is lost) Notes Qt::Horizontal 40 20 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander allow role_transition clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class default_role default_regex results_frame table_results raw_results notes clear_class clicked() tclass clearSelection() 299 312 147 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.1.1/setoolsgui/apol/rolequery.py000066400000000000000000000200211314142262400207300ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import RoleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..rolemodel import RoleTableModel, role_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class RoleQueryTab(AnalysisTab): """Role browser and query tab.""" def __init__(self, parent, policy, perm_map): super(RoleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = RoleQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.rolequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/rolequery.ui") # populate role list self.role_model = SEToolsListModel(self) self.role_model.item_list = sorted(r for r in self.policy.roles()) self.roles.setModel(self.role_model) # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # set up results self.table_results_model = RoleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.rolequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.roles.doubleClicked.connect(self.get_detail) self.roles.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.types.selectionModel().selectionChanged.connect(self.set_types) self.invert_types.clicked.connect(self.invert_type_selection) self.buttonBox.clicked.connect(self.run) # # User browser # def get_detail(self): # .ui is set for single item selection. index = self.roles.selectedIndexes()[0] item = self.role_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) role_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the role name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Role name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Type criteria # def set_types(self): selected_types = [] for index in self.types.selectionModel().selectedIndexes(): selected_types.append(self.type_model.data(index, Qt.UserRole)) self.query.types = selected_types def invert_type_selection(self): invert_list_selection(self.types.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["types"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["types"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.types_equal = self.types_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} role(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the types column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/rolequery.ui000066400000000000000000000422321314142262400207250ustar00rootroot00000000000000 RoleQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Roles 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Role Browser 0 0 16777215 16777215 Search Criteria Types 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching role will have a role set equal to the selected types. Equal A matching role will have any of the selected types. Any true 0 0 250 16777215 Match the type set of the role. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Role Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander roles name name_regex types types_any types_equal clear_types invert_types results_frame table_results raw_results notes clear_types clicked() types clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/sensitivityquery.py000066400000000000000000000163611314142262400223750ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import SensitivityQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsmodel import MLSComponentTableModel, sensitivity_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class SensitivityQueryTab(AnalysisTab): """Sensitivity browser and query tab.""" def __init__(self, parent, policy, perm_map): super(SensitivityQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = SensitivityQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.sensitivityquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/sensitivityquery.ui") # populate sensitivity list self.sensitivity_model = SEToolsListModel(self) self.sensitivity_model.item_list = sorted(self.policy.sensitivities()) self.sens.setModel(self.sensitivity_model) # set up results self.table_results_model = MLSComponentTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.sensitivityquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.sens.doubleClicked.connect(self.get_detail) self.sens.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Sensitivity browser # def get_detail(self): # .ui is set for single item selection. index = self.sens.selectedIndexes()[0] item = self.sensitivity_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) sensitivity_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the sensitivity name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Sensitivity name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} categories found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/sensitivityquery.ui000066400000000000000000000313121314142262400223530ustar00rootroot00000000000000 SensitivityQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Sensitivities 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Sensitivities Browser 0 0 16777215 16777215 Search Criteria QDialogButtonBox::Apply 16777215 120 Sensitivity Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander sens name name_regex results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/summary.py000066400000000000000000000137351314142262400204140ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import MLSRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsrulemodel import MLSRuleTableModel from .analysistab import AnalysisTab from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_textedits, save_checkboxes, save_textedits class SummaryTab(AnalysisTab): """An SELinux policy summary.""" def __init__(self, parent, policy, perm_map): super(SummaryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.setupUi(policy) def setupUi(self, p): self.load_ui("apol/summary.ui") # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # Populate policy stats mls = "enabled" if p.mls else "disabled" self.policy_version.setText(str(p.version)) self.mls.setText(mls) self.handle_unknown.setText(p.handle_unknown.name) self.class_count.setText(str(p.class_count)) self.perms_count.setText(str(p.permission_count)) self.type_count.setText(str(p.type_count)) self.attribute_count.setText(str(p.type_attribute_count)) self.user_count.setText(str(p.user_count)) self.role_count.setText(str(p.role_count)) self.bool_count.setText(str(p.boolean_count)) self.allow_count.setText(str(p.allow_count)) self.neverallow_count.setText(str(p.neverallow_count)) self.auditallow_count.setText(str(p.auditallow_count)) self.dontaudit_count.setText(str(p.dontaudit_count)) self.type_transition_count.setText(str(p.type_transition_count)) self.type_change_count.setText(str(p.type_change_count)) self.type_member_count.setText(str(p.type_member_count)) self.role_allow_count.setText(str(p.role_allow_count)) self.role_transition_count.setText(str(p.role_transition_count)) self.constrain_count.setText(str(p.constraint_count)) self.validatetrans_count.setText(str(p.validatetrans_count)) self.permissive_count.setText(str(p.permissives_count)) self.default_count.setText(str(p.default_count)) self.typebounds_count.setText(str(p.typebounds_count)) self.allowxperm_count.setText(str(p.allowxperm_count)) self.neverallowxperm_count.setText(str(p.neverallowxperm_count)) self.auditallowxperm_count.setText(str(p.auditallowxperm_count)) self.dontauditxperm_count.setText(str(p.dontauditxperm_count)) self.initsid_count.setText(str(p.initialsids_count)) self.fs_use_count.setText(str(p.fs_use_count)) self.genfscon_count.setText(str(p.genfscon_count)) self.portcon_count.setText(str(p.portcon_count)) self.netifcon_count.setText(str(p.netifcon_count)) self.nodecon_count.setText(str(p.nodecon_count)) if p.mls: self.sensitivity_count.setText(str(p.level_count)) self.category_count.setText(str(p.category_count)) self.range_transition_count.setText(str(p.range_transition_count)) self.mlsconstrain_count.setText(str(p.mlsconstraint_count)) self.mlsvalidatetrans_count.setText(str(p.mlsvalidatetrans_count)) else: self.sens_label.setEnabled(False) self.sens_label.setToolTip("MLS is disabled in this policy.") self.cats_label.setEnabled(False) self.cats_label.setToolTip("MLS is disabled in this policy.") self.range_trans_label.setEnabled(False) self.range_trans_label.setToolTip("MLS is disabled in this policy.") self.mlsconstrain_label.setEnabled(False) self.mlsconstrain_label.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans_label.setEnabled(False) self.mlsvalidatetrans_label.setToolTip("MLS is disabled in this policy.") self.sensitivity_count.setEnabled(False) self.sensitivity_count.setToolTip("MLS is disabled in this policy.") self.category_count.setEnabled(False) self.category_count.setToolTip("MLS is disabled in this policy.") self.range_transition_count.setEnabled(False) self.range_transition_count.setToolTip("MLS is disabled in this policy.") self.mlsconstrain_count.setEnabled(False) self.mlsconstrain_count.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans_count.setEnabled(False) self.mlsvalidatetrans_count.setToolTip("MLS is disabled in this policy.") # Fill policy capabilities list self.polcaps.addItems([str(c) for c in p.polcaps()]) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} save_checkboxes(self, settings, ["notes_expander"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["notes_expander"]) load_textedits(self, settings, ["notes"]) setools-4.1.1/setoolsgui/apol/summary.ui000066400000000000000000000674431314142262400204060ustar00rootroot00000000000000 SummaryTab 0 0 774 749 QAbstractScrollArea::AdjustToContents true 0 0 772 747 0 0 6 6 6 6 3 0 0 16777215 20 12 75 true SELinux Policy Summary Policy Properties 75 true Policy Version: 0 75 true Unknown Permissions: 0 75 true MLS: 0 0 0 200 60 true 75 true Policy Capabilities: 0 0 Show or hide the notes field (no data is lost) Notes Rule Counts 75 true allow: 75 true allowxperm: 75 true auditallow: 75 true auditallowxperm: 75 true neverallow: 75 true neverallowxperm: 75 true dontaudit: 75 true dontauditxperm: 75 true type_transition: 75 true type_member: 75 true type_change: 0 0 0 0 0 0 0 0 0 0 0 75 true role_transition: 75 true allow (role): 75 true range_transition: 0 0 0 Component Counts 75 true Classes: 0 75 true Permissions: 75 true Types: 0 0 75 true Attributes: 0 75 true Roles: 75 true Users: 75 true Booleans: 75 true Sensitivities: 75 true Categories: 0 0 0 0 0 Constraint Counts 75 true constrain: 0 75 true validatetrans: 0 75 true mlsconstrain: 0 75 true mlsvalidatetrans: 0 Other 75 true Permissive Types: 0 75 true Defaults: 0 75 true Typebounds: 0 Labeling Counts 75 true Initial SIDs: 75 true fs_use_*: 75 true Genfscon: 75 true Portcon: 75 true Nodecon: 0 0 0 0 0 75 true Netifcon: 0 0 0 0 80 Optionally enter notes here about the query. Enter notes here. 0 0 Show: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter notes_expander polcaps notes notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 setools-4.1.1/setoolsgui/apol/terulequery.py000066400000000000000000000446371314142262400213120ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TERuleQuery from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..terulemodel import TERuleTableModel from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TERuleQueryTab(AnalysisTab): """A Type Enforcement rule query.""" def __init__(self, parent, policy, perm_map): super(TERuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TERuleQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.terulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/terulequery.ui") # set up source/target autocompletion typeattr_completion_list = [str(t) for t in self.policy.types()] typeattr_completion_list.extend(str(a) for a in self.policy.typeattributes()) typeattr_completer_model = QStringListModel(self) typeattr_completer_model.setStringList(sorted(typeattr_completion_list)) self.typeattr_completion = QCompleter() self.typeattr_completion.setModel(typeattr_completer_model) self.source.setCompleter(self.typeattr_completion) self.target.setCompleter(self.typeattr_completion) # set up default autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.default_type.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() self.clear_xperm_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # populate bool list self.bool_model = SEToolsListModel(self) self.bool_model.item_list = sorted(self.policy.bools()) self.bool_criteria.setModel(self.bool_model) # set up results self.table_results_model = TERuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.terulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.set_default_regex(self.default_regex.isChecked()) self.toggle_xperm_criteria() self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.allowxperm.toggled.connect(self.toggle_xperm_criteria) self.auditallowxperm.toggled.connect(self.toggle_xperm_criteria) self.neverallowxperm.toggled.connect(self.toggle_xperm_criteria) self.dontauditxperm.toggled.connect(self.toggle_xperm_criteria) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.xperms.textEdited.connect(self.clear_xperm_error) self.xperms.editingFinished.connect(self.set_xperm) self.default_type.textEdited.connect(self.clear_default_error) self.default_type.editingFinished.connect(self.set_default_type) self.default_regex.toggled.connect(self.set_default_regex) self.bool_criteria.selectionModel().selectionChanged.connect(self.set_bools) # # Ruletype criteria # def _set_ruletypes(self, value): self.allow.setChecked(value) self.allowxperm.setChecked(value) self.auditallow.setChecked(value) self.auditallowxperm.setChecked(value) self.neverallow.setChecked(value) self.neverallowxperm.setChecked(value) self.dontaudit.setChecked(value) self.dontauditxperm.setChecked(value) self.type_transition.setChecked(value) self.type_member.setChecked(value) self.type_change.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source type/attribute of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source type/attribute error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target type/attribute of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/attribute error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes self.perms_model.set_classes(selected_classes) def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Extended permission criteria # def toggle_xperm_criteria(self): mode = any((self.allowxperm.isChecked(), self.auditallowxperm.isChecked(), self.neverallowxperm.isChecked(), self.dontauditxperm.isChecked())) self.xperms.setEnabled(mode) self.xperms_equal.setEnabled(mode) def clear_xperm_error(self): self.clear_criteria_error(self.xperms, "Match the extended permissions of the rule. " "Comma-separated permissions or ranges of permissions.") def set_xperm(self): xperms = [] try: text = self.xperms.text() if text: for item in self.xperms.text().split(","): rng = item.split("-") if len(rng) == 2: xperms.append((int(rng[0], base=16), int(rng[1], base=16))) elif len(rng) == 1: xperms.append((int(rng[0], base=16), int(rng[0], base=16))) else: raise ValueError("Enter an extended permission or extended permission " "range, e.g. 0x5411 or 0x8800-0x88ff.") self.query.xperms = xperms else: self.query.xperms = None except Exception as ex: self.log.error("Extended permissions error: {0}".format(ex)) self.set_criteria_error(self.xperms, ex) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_type, "Match the default type the rule.") def set_default_type(self): self.query.default_regex = self.default_regex.isChecked() try: self.query.default = self.default_type.text() except Exception as ex: self.log.error("Default type error: {0}".format(ex)) self.set_criteria_error(self.default_type, ex) def set_default_regex(self, state): self.log.debug("Setting default_regex {0}".format(state)) self.query.default_regex = state self.clear_default_error() self.set_default_type() # # Boolean criteria # def set_bools(self): selected_bools = [] for index in self.bool_criteria.selectionModel().selectedIndexes(): selected_bools.append(self.bool_model.data(index, Qt.UserRole)) self.query.boolean = selected_bools # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "allowxperm", "auditallow", "auditallowxperm", "neverallow", "neverallowxperm", "dontaudit", "dontauditxperm", "type_transition", "type_change", "type_member", "source_indirect", "source_regex", "target_indirect", "target_regex", "perms_subset", "xperms_equal", "default_regex", "bools_equal"]) save_lineedits(self, settings, ["source", "target", "xperms", "default_type"]) save_listviews(self, settings, ["tclass", "perms", "bool_criteria"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["allow", "allowxperm", "auditallow", "auditallowxperm", "neverallow", "neverallowxperm", "dontaudit", "dontauditxperm", "type_transition", "type_change", "type_member", "criteria_expander", "notes_expander", "source_indirect", "source_regex", "target_indirect", "target_regex", "perms_subset", "xperms_equal", "default_regex", "bools_equal"]) load_lineedits(self, settings, ["source", "target", "xperms", "default_type"]) load_listviews(self, settings, ["tclass", "perms", "bool_criteria"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] max_results = 0 if self.allow.isChecked(): rule_types.append("allow") max_results += self.policy.allow_count if self.allowxperm.isChecked(): rule_types.append("allowxperm") max_results += self.policy.allowxperm_count if self.auditallow.isChecked(): rule_types.append("auditallow") max_results += self.policy.auditallow_count if self.auditallowxperm.isChecked(): rule_types.append("auditallowxperm") max_results += self.policy.auditallowxperm_count if self.neverallow.isChecked(): rule_types.append("neverallow") max_results += self.policy.neverallow_count if self.neverallowxperm.isChecked(): rule_types.append("neverallowxperm") max_results += self.policy.neverallowxperm_count if self.dontaudit.isChecked(): rule_types.append("dontaudit") max_results += self.policy.dontaudit_count if self.dontauditxperm.isChecked(): rule_types.append("dontauditxperm") max_results += self.policy.dontauditxperm_count if self.type_transition.isChecked(): rule_types.append("type_transition") max_results += self.policy.type_transition_count if self.type_member.isChecked(): rule_types.append("type_member") max_results += self.policy.type_member_count if self.type_change.isChecked(): rule_types.append("type_change") max_results += self.policy.type_change_count self.query.ruletype = rule_types self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() self.query.perms_subset = self.perms_subset.isChecked() self.query.boolean_equal = self.bools_equal.isChecked() # if query is broad, show warning. if not any((self.query.source, self.query.target, self.query.tclass, self.query.perms, self.query.xperms, self.query.default, self.query.boolean)) \ and max_results > 1000: reply = QMessageBox.question( self, "Continue?", "This is a broad query, estimated to return {0} results. Continue?". format(max_results), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} type enforcement rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(4) > 400: header.resizeSection(4, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/terulequery.ui000066400000000000000000001051741314142262400212710ustar00rootroot00000000000000 TERuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 1 Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true Qt::Horizontal 40 20 0 0 Show: 0 0 16777215 20 12 75 true Type Enforcement Rule Query 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Type/Attribute 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Auditallow Dontaudit Qt::Horizontal 40 20 Allow true Neverallow Clear false Neverallowxperms Allowxperms true Auditallowxperms Type_transition Type_change Type_member Dontauditxperms Default Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the default type. Regex 16777215 100 Source Type/Attribute 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 Use regular expressions to match the source type/attribute. Regex If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection Booleans in Conditional Expression 6 6 6 6 3 0 0 250 16777215 Booleans used in the rule's conditional expression. QAbstractItemView::ExtendedSelection Qt::Horizontal 40 20 Clear A matching rule will use a set of Booleans in its conditional expression equal to the selected Booleans. Equal Qt::Vertical 20 40 QDialogButtonBox::Apply Permission Set 6 6 6 6 3 A matching rule will have an extended permission set equal to the listed extended permissions. Equal Invert Clear Qt::Horizontal 40 20 A matching rule will have all of the selected permissions. Match All Qt::Vertical 20 40 0 0 250 16777215 The list of permissions common to selected object classes. QAbstractItemView::ExtendedSelection Enter extended permissions here. ruletype_criteria source_criteria target_criteria class_criteria perms_criteria default_criteria booleans_criteria buttonBox SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander allow neverallow auditallow dontaudit clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class perms clear_perms invert_perms perms_subset default_type default_regex bool_criteria clear_bools bools_equal results_frame table_results raw_results notes clear_bools clicked() bool_criteria clearSelection() 576 430 454 447 clear_class clicked() tclass clearSelection() 299 312 147 330 clear_perms clicked() perms clearSelection() 565 312 448 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776
setools-4.1.1/setoolsgui/apol/typeattrquery.py000066400000000000000000000202121314142262400216450ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TypeAttributeQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..typeattrmodel import TypeAttributeTableModel, typeattr_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TypeAttributeQueryTab(AnalysisTab): """TypeAttribute browser and query tab.""" def __init__(self, parent, policy, perm_map): super(TypeAttributeQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TypeAttributeQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.typeattrquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/typeattrquery.ui") # populate attr list self.attr_model = SEToolsListModel(self) self.attr_model.item_list = sorted(r for r in self.policy.typeattributes()) self.attrs.setModel(self.attr_model) # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # set up results self.table_results_model = TypeAttributeTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.typeattrquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.attrs.doubleClicked.connect(self.get_detail) self.attrs.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.types.selectionModel().selectionChanged.connect(self.set_types) self.invert_types.clicked.connect(self.invert_type_selection) self.buttonBox.clicked.connect(self.run) # # Attribute browser # def get_detail(self): # .ui is set for single item selection. index = self.attrs.selectedIndexes()[0] item = self.attr_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) typeattr_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the attribute name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Type attribute name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Type criteria # def set_types(self): selected_types = [] for index in self.types.selectionModel().selectedIndexes(): selected_types.append(self.type_model.data(index, Qt.UserRole)) self.query.types = selected_types def invert_type_selection(self): invert_list_selection(self.types.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["types"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["types"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.types_equal = self.types_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} attribute(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the types column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/typeattrquery.ui000066400000000000000000000423241314142262400216420ustar00rootroot00000000000000 TypeAttributeQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Type Attributes 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Attribute Browser 0 0 16777215 16777215 Search Criteria Types 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching attribute will have a role set equal to the selected types. Equal A matching attribute will have any of the selected types. Any true 0 0 250 16777215 Match the type set of the attribute. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Attribute Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the attribute's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander attrs name name_regex types types_any types_equal clear_types invert_types results_frame table_results raw_results notes clear_types clicked() types clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/typequery.py000066400000000000000000000204211314142262400207540ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TypeQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..typemodel import TypeTableModel, type_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TypeQueryTab(AnalysisTab): """Type browser and query tab.""" def __init__(self, parent, policy, perm_map): super(TypeQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TypeQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.typequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/typequery.ui") # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # populate attribute list self.attr_model = SEToolsListModel(self) self.attr_model.item_list = sorted(self.policy.typeattributes()) self.attrs.setModel(self.attr_model) # set up results self.table_results_model = TypeTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.typequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.types.doubleClicked.connect(self.get_detail) self.types.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.attrs.selectionModel().selectionChanged.connect(self.set_attrs) self.invert_attrs.clicked.connect(self.invert_attr_selection) self.buttonBox.clicked.connect(self.run) # # Type browser # def get_detail(self): # .ui is set for single item selection. index = self.types.selectedIndexes()[0] item = self.type_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) type_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the type name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Type name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Attribute criteria # def set_attrs(self): selected_attrs = [] for index in self.attrs.selectionModel().selectedIndexes(): selected_attrs.append(self.attr_model.data(index, Qt.UserRole)) self.query.attrs = selected_attrs def invert_attr_selection(self): invert_list_selection(self.attrs.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "attrs_any", "attrs_equal", "permissive"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["attrs"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "attrs_any", "attrs_equal", "permissive"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["attrs"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.name_regex = self.name_regex.isChecked() self.query.attrs_equal = self.attrs_equal.isChecked() self.query.permissive = self.permissive.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} type(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/typequery.ui000066400000000000000000000441361314142262400207520ustar00rootroot00000000000000 UserQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Types 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Type Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Permissive A matching type will be permissive. Permisive Attributes 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching type will have an attribute set equal to the selected attributes. Equal A matching type will have any of the selected attributes. Any true 0 0 250 16777215 Match the attribute set of the type. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Type Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander types name name_regex permissive attrs attrs_any attrs_equal clear_attrs invert_attrs results_frame table_results raw_results notes clear_attrs clicked() attrs clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/userquery.py000066400000000000000000000251511314142262400207560ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import UserQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..usermodel import UserTableModel, user_detail from .analysistab import AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class UserQueryTab(AnalysisTab): """User browser and query tab.""" def __init__(self, parent, policy, perm_map): super(UserQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = UserQuery(policy) self.setupUi() def __del__(self): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.userquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/userquery.ui") # populate user list self.user_model = SEToolsListModel(self) self.user_model.item_list = sorted(self.policy.users()) self.users.setModel(self.user_model) # populate role list self.role_model = SEToolsListModel(self) self.role_model.item_list = sorted(r for r in self.policy.roles() if r != "object_r") self.roles.setModel(self.role_model) # set up results self.table_results_model = UserTableModel(self, self.policy.mls) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() if self.policy.mls: self.clear_level_error() self.clear_range_error() else: # disable level and range criteria self.level_criteria.setEnabled(False) self.level_criteria.setToolTip("MLS is disabled in this policy.") self.level.setToolTip("MLS is disabled in this policy.") self.level_exact.setToolTip("MLS is disabled in this policy.") self.level_dom.setToolTip("MLS is disabled in this policy.") self.level_domby.setToolTip("MLS is disabled in this policy.") self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.userquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.users.doubleClicked.connect(self.get_detail) self.users.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.roles.selectionModel().selectionChanged.connect(self.set_roles) self.invert_roles.clicked.connect(self.invert_role_selection) self.level.textEdited.connect(self.clear_level_error) self.level.editingFinished.connect(self.set_level) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) self.buttonBox.clicked.connect(self.run) # # User browser # def get_detail(self): # .ui is set for single item selection. index = self.users.selectedIndexes()[0] item = self.user_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) user_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the user name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("User name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Role criteria # def set_roles(self): selected_roles = [] for index in self.roles.selectionModel().selectedIndexes(): selected_roles.append(self.role_model.data(index, Qt.UserRole)) self.query.roles = selected_roles def invert_role_selection(self): invert_list_selection(self.roles.selectionModel()) # # Default level criteria # def clear_level_error(self): self.clear_criteria_error(self.level, "Match the default level of the user.") def set_level(self): try: self.query.level = self.level.text() except Exception as ex: self.log.info("Level criterion error: " + str(ex)) self.set_criteria_error(self.level, ex) # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the default range of the user.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Range criterion error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "roles_any", "roles_equal", "level_exact", "level_dom", "level_domby", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "level", "range_"]) save_listviews(self, settings, ["roles"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "roles_any", "roles_equal", "level_exact", "level_dom", "level_domby", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "level", "range_"]) load_listviews(self, settings, ["roles"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.roles_equal = self.roles_equal.isChecked() self.query.level_dom = self.level_dom.isChecked() self.query.level_domby = self.level_domby.isChecked() self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} user(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.1.1/setoolsgui/apol/userquery.ui000066400000000000000000000612621314142262400207460ustar00rootroot00000000000000 UserQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true SELinux Users 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal User Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Default MLS Level 6 6 6 6 3 0 0 150 20 250 16777215 The level criterion will match if it is equal to the user's default level. Equal true The level criterion will match if it dominates the user's default level. Dominate The level criterion will match if it is dominated by the user's default level. Dominated Roles 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching user will have a role set equal to the selected roles. Equal A matching user will have any of the selected roles. Any true 0 0 250 16777215 Match the role set of the user. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 User Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the user's name. Regex 16777215 16777215 MLS Range 6 6 6 6 3 0 0 150 20 250 16777215 The range criterion will match if it is equal to the user's range. Equal true The range criterion will match if it is a subset of the user's range. Subset The range criterion will match if it overlaps the user's range. Overlap The range criterion will match if it is a superset of the user's range. Superset Qt::Vertical 20 40 QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander users name name_regex roles roles_any roles_equal clear_roles invert_roles level level_exact level_dom level_domby range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes clear_roles clicked() roles clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.1.1/setoolsgui/apol/workspace.py000066400000000000000000000176521314142262400207170ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import re import logging import setools from setools.policyrep.symbol import PolicySymbol from PyQt5.QtCore import Qt, QItemSelectionModel def save_checkboxes(tab, settings, checkboxes): """ Save settings from the checkable buttons (e.g. QCheckbox) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. checkboxes A list of attribute names (str) of buttons in the tab. """ for entry in checkboxes: checkbox = getattr(tab, entry) settings[entry] = checkbox.isChecked() def load_checkboxes(tab, settings, checkboxes): """ Load settings into the checkable buttons (e.g. QCheckbox) in the tab. Parameters: tab The tab object. settings The dictionary of settings. checkboxes A list of attribute names (str) of buttons in the tab. """ log = logging.getLogger(__name__) # next set options for entry in checkboxes: checkbox = getattr(tab, entry) try: checkbox.setChecked(bool(settings[entry])) except KeyError: log.warning("{0} option missing from settings file.".format(entry)) def save_lineedits(tab, settings, lines): """ Save settings into the QLineEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. lines A list of attribute names (str) of QLineEdits in the tab. """ # set line edits for entry in lines: lineedit = getattr(tab, entry) settings[entry] = lineedit.text() def load_lineedits(tab, settings, lines): """ Load settings into the QLineEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. lines A list of attribute names (str) of QLineEdits in the tab. """ log = logging.getLogger(__name__) # set line edits for entry in lines: lineedit = getattr(tab, entry) try: lineedit.setText(str(settings[entry])) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) def save_textedits(tab, settings, edits): """ Save settings into the QTextEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. edits A list of attribute names (str) of QTextEdits in the tab. """ # set line edits for entry in edits: textedit = getattr(tab, entry) settings[entry] = textedit.toPlainText() def load_textedits(tab, settings, edits): """ Load settings into the QTextEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. edits A list of attribute names (str) of QTextEdits in the tab. """ log = logging.getLogger(__name__) # set line edits for entry in edits: textedit = getattr(tab, entry) try: textedit.setPlainText(str(settings[entry])) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) def save_listviews(tab, settings, listviews): """ Save settings from the QListView selection(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. listviews A list of attribute names (str) of QListViews in the tab. """ for entry in listviews: listview = getattr(tab, entry) datamodel = listview.model() selections = [] for index in listview.selectedIndexes(): item = datamodel.data(index, Qt.DisplayRole) selections.append(item) settings[entry] = selections def load_listviews(tab, settings, listviews): """ Load settings into the QListView selection(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. listviews A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) # set list selections for entry in listviews: try: selections = list(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue except TypeError: msg = "Invalid list for {0} criteria: {1!r}".format(entry, settings[entry]) log.critical(msg) raise TypeError(msg) if not selections: continue listview = getattr(tab, entry) selectionmodel = listview.selectionModel() selectionmodel.clear() datamodel = listview.selectionModel().model() for row in range(datamodel.rowCount()): index = datamodel.createIndex(row, 0) item = datamodel.data(index, Qt.DisplayRole) if item in selections: selectionmodel.select(index, QItemSelectionModel.Select) def save_comboboxes(tab, settings, comboboxes): """ Save settings from the QComboBox selection in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. comboboxes A list of attribute names (str) of QListViews in the tab. """ for entry in comboboxes: combobox = getattr(tab, entry) settings[entry] = combobox.currentData(Qt.DisplayRole) def load_comboboxes(tab, settings, comboboxes): """ Load settings into the QComboBox selection in the tab. Parameters: tab The tab object. settings The dictionary of settings. comboboxes A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) for entry in comboboxes: try: selection = str(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue combobox = getattr(tab, entry) combobox.setCurrentText(selection) def save_spinboxes(tab, settings, spinboxes): """ Save settings from the QSpinBox value in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. spinboxes A list of attribute names (str) of QListViews in the tab. """ for entry in spinboxes: spinbox = getattr(tab, entry) settings[entry] = spinbox.value() def load_spinboxes(tab, settings, spinboxes): """ Load settings into the QSpinBox value in the tab. Parameters: tab The tab object. settings The dictionary of settings. spinboxes A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) for entry in spinboxes: try: value = int(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue except (ValueError, TypeError) as ex: msg = "Invalid value for {0} criteria: {1!r}.".format(entry, settings[entry]) log.critical(msg) raise ex.__class__(msg) spinbox = getattr(tab, entry) spinbox.setValue(value) setools-4.1.1/setoolsgui/boolmodel.py000066400000000000000000000034711314142262400177340ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from .details import DetailsPopup from .models import SEToolsTableModel def boolean_detail(parent, boolean): """ Create a dialog box for Booleanean details. Parameters: parent The parent Qt Widget bool The boolean """ detail = DetailsPopup(parent, "Boolean detail: {0}".format(boolean)) detail.append_header("Default State: {0}".format(boolean.state)) detail.show() class BooleanTableModel(SEToolsTableModel): """Table-based model for booleans.""" headers = ["Name", "Default State"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() boolean = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(boolean) elif col == 1: return str(boolean.state) elif role == Qt.UserRole: # get the whole rule for boolean boolean return boolean setools-4.1.1/setoolsgui/boundsmodel.py000066400000000000000000000026411314142262400202710ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class BoundsTableModel(SEToolsTableModel): """Table-based model for *bounds.""" headers = ["Rule Type", "Parent", "Child"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.ruletype.name elif col == 1: return str(item.parent) elif col == 2: return str(item.child) elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/commonmodel.py000066400000000000000000000036371314142262400202750ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.policyrep.exception import NoCommon from .details import DetailsPopup from .models import SEToolsTableModel def common_detail(parent, common): """ Create a dialog box for common perm set details. Parameters: parent The parent Qt Widget class_ The type """ detail = DetailsPopup(parent, "Common detail: {0}".format(common)) detail.append_header("Permissions ({0}):".format(len(common.perms))) for p in sorted(common.perms): detail.append(" {0}".format(p)) detail.show() class CommonTableModel(SEToolsTableModel): """Table-based model for common permission sets.""" headers = ["Name", "Permissions"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: return ", ".join(sorted(str(p) for p in item.perms)) elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/constraintmodel.py000066400000000000000000000033311314142262400211600ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.policyrep.exception import ConstraintUseError from .models import SEToolsTableModel class ConstraintTableModel(SEToolsTableModel): """A table-based model for constraints.""" headers = ["Rule Type", "Class", "Permissions", "Expression"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return str(rule.tclass) elif col == 2: try: return ", ".join(sorted(rule.perms)) except ConstraintUseError: return None elif col == 3: return rule._expression_str(rule.expression()) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/defaultmodel.py000066400000000000000000000031571314142262400204260ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class DefaultTableModel(SEToolsTableModel): """Table-based model for default_*.""" headers = ["Rule Type", "Class", "Default", "Default Range"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.ruletype.name elif col == 1: return str(item.tclass) elif col == 2: return item.default.name elif col == 3: try: return item.default_range.name except AttributeError: pass elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/detail_popup.ui000066400000000000000000000022101314142262400204200ustar00rootroot00000000000000 DetailsPopup 0 0 400 300 Dialog Qt::Horizontal QDialogButtonBox::Close buttonBox clicked(QAbstractButton*) DetailsPopup close() 248 254 157 274 setools-4.1.1/setoolsgui/details.py000066400000000000000000000036161314142262400174060ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtGui import QFont, QTextCursor from PyQt5.QtWidgets import QDialog from .widget import SEToolsWidget class DetailsPopup(SEToolsWidget, QDialog): """A generic non-modal popup with a text field to write detailed info.""" # TODO: make the font changes relative # instead of setting absolute values def __init__(self, parent, title=None): super(DetailsPopup, self).__init__(parent) self.log = logging.getLogger(__name__) self.setupUi(title) def setupUi(self, title): self.load_ui("detail_popup.ui") if title: self.title = title @property def title(self): self.windowTitle(self) @title.setter def title(self, text): self.setWindowTitle(text) def append(self, text): self.contents.setFontWeight(QFont.Normal) self.contents.setFontPointSize(9) self.contents.append(text) def append_header(self, text): self.contents.setFontWeight(QFont.Black) self.contents.setFontPointSize(11) self.contents.append(text) def show(self): self.contents.moveCursor(QTextCursor.Start) super(DetailsPopup, self).show() setools-4.1.1/setoolsgui/fsusemodel.py000066400000000000000000000026341314142262400201260ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class FSUseTableModel(SEToolsTableModel): """Table-based model for fs_use_*.""" headers = ["Ruletype", "FS Type", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.fs elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/genfsconmodel.py000066400000000000000000000034621314142262400206030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import stat from PyQt5.QtCore import Qt from .models import SEToolsTableModel class GenfsconTableModel(SEToolsTableModel): """Table-based model for genfscons.""" headers = ["FS Type", "Path", "File Type", "Context"] _filetype_to_text = { 0: "Any", stat.S_IFBLK: "Block", stat.S_IFCHR: "Character", stat.S_IFDIR: "Directory", stat.S_IFIFO: "Pipe (FIFO)", stat.S_IFREG: "Regular File", stat.S_IFLNK: "Symbolic Link", stat.S_IFSOCK: "Socket"} def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.fs elif col == 1: return rule.path elif col == 2: return self._filetype_to_text[rule.filetype] elif col == 3: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/getdetailslist.py000066400000000000000000000023521314142262400207760ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtGui import QCursor from PyQt5.QtWidgets import QAction, QListView, QMenu class GetDetailsListView(QListView): """A QListView widget with more details context menu.""" def __init__(self, parent): super(GetDetailsListView, self).__init__(parent) # set up right-click context menu self.get_detail = QAction("More details...", self) self.menu = QMenu(self) self.menu.addAction(self.get_detail) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) setools-4.1.1/setoolsgui/initsidmodel.py000066400000000000000000000025121314142262400204370ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class InitialSIDTableModel(SEToolsTableModel): """Table-based model for initial SIDs.""" headers = ["SID", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(rule) elif col == 1: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/logtosignal.py000066400000000000000000000026351314142262400203030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from logging import Formatter, Handler, INFO from PyQt5.QtCore import pyqtSignal, QObject class LogHandlerToSignal(Handler, QObject): """ A Python logging Handler that sends log messages over Qt signals. By default the handler level is set to logging.INFO and only the message is signalled. Qt signals: message (str) A message from the Python logging system. """ message = pyqtSignal(str) def __init__(self): Handler.__init__(self) QObject.__init__(self) self.setLevel(INFO) self.setFormatter(Formatter('%(message)s')) def emit(self, record): msg = self.format(record) if msg: self.message.emit(msg) setools-4.1.1/setoolsgui/mlsmodel.py000066400000000000000000000045231314142262400175730ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from .details import DetailsPopup from .models import SEToolsTableModel def _mls_detail(parent, obj, objtype): """ Create a dialog box for category or sensitivity details. Parameters: parent The parent Qt Widget type_ The type """ detail = DetailsPopup(parent, "{0} detail: {1}".format(objtype, obj)) aliases = sorted(obj.aliases()) detail.append_header("Aliases ({0}):".format(len(aliases))) for a in aliases: detail.append(" {0}".format(a)) detail.show() def category_detail(parent, obj): """ Create a dialog box for category details. Parameters: parent The parent Qt Widget type_ The type """ _mls_detail(parent, obj, "Category") def sensitivity_detail(parent, obj): """ Create a dialog box for sensitivity details. Parameters: parent The parent Qt Widget type_ The type """ _mls_detail(parent, obj, "Sensitivity") class MLSComponentTableModel(SEToolsTableModel): """Table-based model for sensitivities and categories.""" headers = ["Name", "Aliases"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: return ", ".join(sorted(str(a) for a in item.aliases())) elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/mlsrulemodel.py000066400000000000000000000031401314142262400204550ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class MLSRuleTableModel(SEToolsTableModel): """A table-based model for MLS rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Default Range"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return str(rule.source) elif col == 2: return str(rule.target) elif col == 3: return str(rule.tclass) elif col == 4: return str(rule.default) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/models.py000066400000000000000000000113001314142262400172310ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import QAbstractListModel, QItemSelectionModel, QAbstractTableModel, \ QModelIndex, QStringListModel, Qt from setools.policyrep.exception import NoCommon def invert_list_selection(selection_model): """Invert the selection of a list-based model.""" model = selection_model.model() rowcount = model.rowCount() for row in range(rowcount): index = model.createIndex(row, 0) selection_model.select(index, QItemSelectionModel.Toggle) class SEToolsListModel(QAbstractListModel): """ The purpose of this model is to have the objects return their string representations for Qt.DisplayRole and return the object for Qt.UserRole. Some Python list-like functions are provided for altering the model: append and remove """ def __init__(self, parent): super(SEToolsListModel, self).__init__(parent) self.log = logging.getLogger(__name__) self._item_list = None @property def item_list(self): return self._item_list @item_list.setter def item_list(self, item_list): self.beginResetModel() self._item_list = item_list self.endResetModel() def rowCount(self, parent=QModelIndex()): if self.item_list: return len(self.item_list) else: return 0 def columnCount(self, parent=QModelIndex()): return 1 def append(self, item): """Append the item to the list.""" index = self.rowCount() self.beginInsertRows(QModelIndex(), index, index) self.item_list.append(item) self.endInsertRows() def remove(self, item): """Remove the first instance of the specified item from the list.""" try: row = self.item_list.index(item) except ValueError: self.log.debug("Attempted to remove item {0!r} but it is not in the list".format(item)) else: self.beginRemoveRows(QModelIndex(), row, row) del self.item_list[row] self.endRemoveRows() def data(self, index, role): if self.item_list and index.isValid(): row = index.row() item = self.item_list[row] if role == Qt.DisplayRole: return str(item) elif role == Qt.UserRole: return item class PermListModel(SEToolsListModel): """ A model that will return the intersection of permissions for the selected classes. If no classes are set, all permissions in the policy will be returned. """ def __init__(self, parent, policy): super(PermListModel, self).__init__(parent) self.policy = policy self.set_classes() def set_classes(self, classes=[]): permlist = set() # start will all permissions. for cls in self.policy.classes(): permlist.update(cls.perms) try: permlist.update(cls.common.perms) except NoCommon: pass # create intersection for cls in classes: cls_perms = cls.perms try: cls_perms.update(cls.common.perms) except NoCommon: pass permlist.intersection_update(cls_perms) self.item_list = sorted(permlist) class SEToolsTableModel(QAbstractTableModel): """Base class for SETools table models.""" headers = [] def __init__(self, parent): super(SEToolsTableModel, self).__init__(parent) self.resultlist = [] def headerData(self, section, orientation, role): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.headers[section] def rowCount(self, parent=QModelIndex()): if self.resultlist: return len(self.resultlist) else: return 0 def columnCount(self, parent=QModelIndex()): return len(self.headers) def data(self, index, role): raise NotImplementedError setools-4.1.1/setoolsgui/netifconmodel.py000066400000000000000000000026621314142262400206070ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class NetifconTableModel(SEToolsTableModel): """Table-based model for netifcons.""" headers = ["Device", "Device Context", "Packet Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(rule.netif) elif col == 1: return str(rule.context) elif col == 2: return str(rule.packet) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/nodeconmodel.py000066400000000000000000000025441314142262400204260ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class NodeconTableModel(SEToolsTableModel): """Table-based model for nodecons.""" headers = ["Network", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return "{0.address}/{0.netmask}".format(rule) elif col == 1: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/objclassmodel.py000066400000000000000000000047061314142262400206030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from itertools import chain from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.policyrep.exception import NoCommon from .details import DetailsPopup from .models import SEToolsTableModel def class_detail(parent, class_): """ Create a dialog box for object class details. Parameters: parent The parent Qt Widget class_ The type """ detail = DetailsPopup(parent, "Object class detail: {0}".format(class_)) try: common = class_.common except NoCommon: pass else: detail.append_header("Inherits: {0}\n".format(common)) detail.append_header("Inherited permissions ({0}):".format(len(common.perms))) for p in sorted(common.perms): detail.append(" {0}".format(p)) detail.append("\n") detail.append_header("Permissions ({0}):".format(len(class_.perms))) for p in sorted(class_.perms): detail.append(" {0}".format(p)) detail.show() class ObjClassTableModel(SEToolsTableModel): """Table-based model for object classes.""" headers = ["Name", "Permissions"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: try: com_perms = item.common.perms except NoCommon: com_perms = [] return ", ".join(sorted(str(p) for p in chain(com_perms, item.perms))) elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/portconmodel.py000066400000000000000000000031171314142262400204620ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class PortconTableModel(SEToolsTableModel): """Table-based model for portcons.""" headers = ["Port/Port Range", "Protocol", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: low, high = rule.ports if low == high: return str(low) else: return "{0}-{1}".format(low, high) elif col == 1: return rule.protocol.name elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/rbacrulemodel.py000066400000000000000000000036771314142262400206100ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.policyrep.exception import RuleUseError from .models import SEToolsTableModel class RBACRuleTableModel(SEToolsTableModel): """A table-based model for RBAC rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Default Role"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return str(rule.source) elif col == 2: return str(rule.target) elif col == 3: try: return str(rule.tclass) except RuleUseError: # role allow return None elif col == 4: # next most common: default try: return str(rule.default) except RuleUseError: return None elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/rolemodel.py000066400000000000000000000040471314142262400177420ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.policyrep.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def role_detail(parent, role): """ Create a dialog box for role details. Parameters: parent The parent Qt Widget role The role """ detail = DetailsPopup(parent, "Role detail: {0}".format(role)) types = sorted(role.types()) detail.append_header("Types ({0}): ".format(len(types))) for t in types: detail.append(" {0}".format(t)) detail.show() class RoleTableModel(SEToolsTableModel): """Table-based model for roles.""" headers = ["Name", "Types"] def data(self, index, role): # There are two roles here. # The parameter, role, is the Qt role # The below item is a role in the list. if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: return ", ".join(sorted(str(t) for t in item.types())) elif role == Qt.UserRole: # get the whole object return item setools-4.1.1/setoolsgui/tableview.py000066400000000000000000000071061314142262400177410ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import csv from PyQt5.QtCore import Qt from PyQt5.QtGui import QKeySequence, QCursor from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMenu, QTableView class SEToolsTableView(QTableView): """QTableView class extended for SETools use.""" def __init__(self, parent): super(SEToolsTableView, self).__init__(parent) # set up right-click context menu self.save_csv_action = QAction("Save table to CSV...", self) self.menu = QMenu(self) self.menu.addAction(self.save_csv_action) # connect signals self.save_csv_action.triggered.connect(self.choose_csv_save_location) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) def event(self, e): if e == QKeySequence.Copy or e == QKeySequence.Cut: datamodel = self.model() selected_text = [] current_row = None current_col = None prev_row = None prev_col = None for index in sorted(self.selectionModel().selectedIndexes()): current_row = index.row() current_col = index.column() if prev_row is not None and current_row != prev_row: selected_text.append('\n') elif prev_col is not None and current_col != prev_col: selected_text.append('\t') selected_text.append(datamodel.data(index, Qt.DisplayRole)) prev_row = current_row prev_col = current_col QApplication.clipboard().setText("".join(selected_text)) return True else: return super(SEToolsTableView, self).event(e) def choose_csv_save_location(self): filename = QFileDialog.getSaveFileName(self, "Save to CSV", "table.csv", "Comma Separated Values Spreadsheet (*.csv);;" "All Files (*)")[0] if filename: self.save_csv(filename) def save_csv(self, filename): """Save the current table data to the specified CSV file.""" datamodel = self.model() row_count = datamodel.rowCount() col_count = datamodel.columnCount() with open(filename, 'w') as fd: writer = csv.writer(fd, quoting=csv.QUOTE_MINIMAL) # write headers csv_row = [] for col in range(col_count): csv_row.append(datamodel.headerData(col, Qt.Horizontal, Qt.DisplayRole)) writer.writerow(csv_row) # write data for row in range(row_count): csv_row = [] for col in range(col_count): index = datamodel.index(row, col) csv_row.append(datamodel.data(index, Qt.DisplayRole)) writer.writerow(csv_row) setools-4.1.1/setoolsgui/terulemodel.py000066400000000000000000000046231314142262400203010ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.policyrep.exception import RuleNotConditional, RuleUseError from .models import SEToolsTableModel class TERuleTableModel(SEToolsTableModel): """A table-based model for TE rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Permissions/Default Type", "Conditional Expression", "Conditional Block"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return str(rule.source) elif col == 2: return str(rule.target) elif col == 3: return str(rule.tclass) elif col == 4: try: if rule.extended: return "{0.xperm_type}: {0.perms:,}".format(rule) else: return ", ".join(sorted(rule.perms)) except RuleUseError: return str(rule.default) elif col == 5: try: return str(rule.conditional) except RuleNotConditional: return None elif col == 6: try: return str(rule.conditional_block) except RuleNotConditional: return None elif role == Qt.UserRole: return rule setools-4.1.1/setoolsgui/treeview.py000066400000000000000000000046501314142262400176120ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt, QModelIndex from PyQt5.QtGui import QKeySequence, QCursor from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMenu, QTreeWidget, \ QTreeWidgetItemIterator class SEToolsTreeWidget(QTreeWidget): """QTreeWidget class extended for SETools use.""" def __init__(self, parent): super(SEToolsTreeWidget, self).__init__(parent) # set up right-click context menu self.copy_tree_action = QAction("Copy Tree...", self) self.menu = QMenu(self) self.menu.addAction(self.copy_tree_action) # connect signals self.copy_tree_action.triggered.connect(self.copy_tree) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) def copy_tree(self): """Copy the tree to the clipboard.""" items = [] inval_index = QModelIndex() it = QTreeWidgetItemIterator(self) prev_depth = 0 while it.value(): depth = 0 item = it.value() parent = item.parent() while parent: depth += 1 parent = parent.parent() if depth < prev_depth: items.extend([" |"*depth, "\n"]) if depth: items.extend([" |"*depth, "--", item.text(0), "\n"]) else: items.extend([item.text(0), "\n"]) prev_depth = depth it += 1 QApplication.clipboard().setText("".join(items)) def event(self, e): if e == QKeySequence.Copy or e == QKeySequence.Cut: self.copy_tree() return True else: return super(SEToolsTreeWidget, self).event(e) setools-4.1.1/setoolsgui/typeattrmodel.py000066400000000000000000000036351314142262400206570ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.policyrep.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def typeattr_detail(parent, attr): """ Create a dialog box for attribute details. Parameters: parent The parent Qt Widget role The role """ detail = DetailsPopup(parent, "Type attribute detail: {0}".format(attr)) types = sorted(attr.expand()) detail.append_header("Types ({0}): ".format(len(types))) for t in types: detail.append(" {0}".format(t)) detail.show() class TypeAttributeTableModel(SEToolsTableModel): """Table-based model for roles.""" headers = ["Name", "Types"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: return ", ".join(sorted(str(t) for t in item.expand())) elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/typemodel.py000066400000000000000000000045751314142262400177700ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.policyrep.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def type_detail(parent, type_): """ Create a dialog box for type details. Parameters: parent The parent Qt Widget type_ The type """ detail = DetailsPopup(parent, "Type detail: {0}".format(type_)) detail.append_header("Permissive: {0}\n".format("Yes" if type_.ispermissive else "No")) attrs = sorted(type_.attributes()) detail.append_header("Attributes ({0}):".format(len(attrs))) for a in attrs: detail.append(" {0}".format(a)) aliases = sorted(type_.aliases()) detail.append_header("\nAliases ({0}):".format(len(aliases))) for a in aliases: detail.append(" {0}".format(a)) detail.show() class TypeTableModel(SEToolsTableModel): """Table-based model for types.""" headers = ["Name", "Attributes", "Aliases", "Permissive"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(item) elif col == 1: return ", ".join(sorted(str(a) for a in item.attributes())) elif col == 2: return ", ".join(sorted(str(a) for a in item.aliases())) elif col == 3 and item.ispermissive: return "Permissive" elif role == Qt.UserRole: return item setools-4.1.1/setoolsgui/usermodel.py000066400000000000000000000053471314142262400177630ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt, QModelIndex from setools.policyrep.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def user_detail(parent, user): """ Create a dialog box for user details. Parameters: parent The parent Qt Widget user The user """ detail = DetailsPopup(parent, "User detail: {0}".format(user)) roles = sorted(user.roles) detail.append_header("Roles ({0}):".format(len(roles))) for r in roles: detail.append(" {0}".format(r)) try: l = user.mls_level r = user.mls_range except MLSDisabled: pass else: detail.append_header("\nDefault MLS Level:") detail.append(" {0}".format(l)) detail.append_header("\nMLS Range:") detail.append(" {0}".format(r)) detail.show() class UserTableModel(SEToolsTableModel): """Table-based model for users.""" headers = ["Name", "Roles", "Default Level", "Range"] def __init__(self, parent, mls): super(UserTableModel, self).__init__(parent) self.col_count = 4 if mls else 2 def columnCount(self, parent=QModelIndex()): return self.col_count def data(self, index, role): if self.resultlist and index.isValid(): if role == Qt.DisplayRole: row = index.row() col = index.column() user = self.resultlist[row] if col == 0: return str(user) elif col == 1: return ", ".join(sorted(str(r) for r in user.roles)) elif col == 2: try: return str(user.mls_level) except MLSDisabled: return None elif col == 3: try: return str(user.mls_range) except MLSDisabled: return None elif role == Qt.UserRole: return user setools-4.1.1/setoolsgui/widget.py000066400000000000000000000024471314142262400172450ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys from errno import ENOENT import pkg_resources from PyQt5.uic import loadUi # Stylesheet that adds a frame around QGroupBoxes stylesheet = "\ QGroupBox {\ border: 1px solid lightgrey;\ margin-top: 0.5em;\ }\ \ QGroupBox::title {\ subcontrol-origin: margin;\ left: 10px;\ padding: 0 3px 0 3px;\ }\ " class SEToolsWidget(object): def load_ui(self, filename): distro = pkg_resources.get_distribution("setools") path = "{0}/setoolsgui/{1}".format(distro.location, filename) loadUi(path, self) self.setStyleSheet(stylesheet) setools-4.1.1/setup.py000066400000000000000000000173001314142262400147170ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function import glob from setuptools import setup import distutils.log as log from distutils.core import Extension from distutils.cmd import Command from distutils.unixccompiler import UnixCCompiler from setuptools.command.build_ext import build_ext import subprocess import sys import os from os.path import join class QtHelpCommand(Command): description = "Build Qt help files." user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): command = ['qcollectiongenerator', 'qhc/apol.qhcp'] self.announce("Building Qt help files", level=log.INFO) self.announce(' '.join(command), level=log.INFO) subprocess.check_call(command) self.announce("Moving Qt help files to setoolsgui/apol") os.rename('qhc/apol.qhc', 'setoolsgui/apol/apol.qhc') os.rename('qhc/apol.qch', 'setoolsgui/apol/apol.qch') class YaccCommand(Command): description = "Build yacc parsers." user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): command = ['bison', '-y', '-d', 'libqpol/policy_parse.y', '-o', 'libqpol/policy_parse.c'] self.announce("Generating parser", level=log.INFO) self.announce(' '.join(command), level=log.INFO) subprocess.check_call(command) class LexCommand(Command): description = "Build lex scanners." user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): command = [ 'flex', '-o', 'libqpol/policy_scan.c', 'libqpol/policy_scan.l'] self.announce("Generating scanner", level=log.INFO) self.announce(' '.join(command), level=log.INFO) subprocess.check_call(command) class BuildExtCommand(build_ext): def run(self): self.run_command('build_yacc') self.run_command('build_lex') build_ext.run(self) base_lib_dirs = ['.', '/usr/lib64', '/usr/lib', '/usr/local/lib'] include_dirs = ['libqpol', 'libqpol/include'] try: base_lib_dirs.insert(0, os.environ["SEPOL_SRC"] + "/src") include_dirs.append(os.environ["SEPOL_SRC"] + "/include") except KeyError: pass try: static_sepol = os.environ['SEPOL'] except KeyError: # try to find libsepol.a. The find_library_file function # chooses dynamic libraries over static ones, so # this assumes that the static lib is in the same directory # as the dynamic lib. dynamic_sepol = UnixCCompiler().find_library_file(base_lib_dirs, 'sepol') if dynamic_sepol is None: print('Unable to find a libsepol.so on your system!') print("Looked in the following directories:\n{}".format("\n".join(base_lib_dirs))) print('Please set the SEPOL or SEPOL_SRC environment variables. Exiting.') exit(1) static_sepol = dynamic_sepol.replace(".so", ".a") if sys.platform.startswith('darwin'): macros=[('DARWIN',1)] else: macros=[] ext_py_mods = [Extension('setools.policyrep._qpol', ['setools/policyrep/qpol.i', 'libqpol/avrule_query.c', 'libqpol/bool_query.c', 'libqpol/bounds_query.c', 'libqpol/class_perm_query.c', 'libqpol/cond_query.c', 'libqpol/constraint_query.c', 'libqpol/context_query.c', 'libqpol/default_object_query.c', 'libqpol/expand.c', 'libqpol/fs_use_query.c', 'libqpol/ftrule_query.c', 'libqpol/genfscon_query.c', 'libqpol/isid_query.c', 'libqpol/iterator.c', 'libqpol/mls_query.c', 'libqpol/mlsrule_query.c', 'libqpol/module.c', 'libqpol/module_compiler.c', 'libqpol/netifcon_query.c', 'libqpol/nodecon_query.c', 'libqpol/permissive_query.c', 'libqpol/polcap_query.c', 'libqpol/policy.c', 'libqpol/policy_define.c', 'libqpol/policy_extend.c', 'libqpol/portcon_query.c', 'libqpol/queue.c', 'libqpol/rbacrule_query.c', 'libqpol/role_query.c', 'libqpol/terule_query.c', 'libqpol/type_query.c', 'libqpol/user_query.c', 'libqpol/policy_parse.c', 'libqpol/policy_scan.c', 'libqpol/xen_query.c'], include_dirs=include_dirs, extra_compile_args=['-Werror', '-Wextra', '-Waggregate-return', '-Wfloat-equal', '-Wformat', '-Wformat=2', '-Winit-self', '-Wmissing-format-attribute', '-Wmissing-include-dirs', '-Wnested-externs', '-Wold-style-definition', '-Wpointer-arith', '-Wredundant-decls', '-Wstrict-prototypes', '-Wunknown-pragmas', '-Wwrite-strings', '-Wno-missing-field-initializers', # SWIG 3.0.2 generates partially-initialized structs '-Wno-unused-parameter', # SWIG generates functions with unused parameters '-Wno-cast-qual', # libsepol uses const-to-nonconst casts '-Wno-shadow', # SWIG generates shadow variables '-Wno-unreachable-code', # Bison generates unreachable code '-fno-exceptions'], swig_opts=['-Ilibqpol/include'], define_macros=macros, extra_objects=[static_sepol])] setup(name='setools', version='4.1.1', description='SELinux Policy tools.', author='Tresys Technology, LLC', author_email='setools@tresys.com', url='https://github.com/TresysTechnology/setools', cmdclass={'build_yacc': YaccCommand, 'build_lex': LexCommand, 'build_ext': BuildExtCommand, 'build_qhc': QtHelpCommand}, packages=['setools', 'setools.diff', 'setools.policyrep', 'setoolsgui', 'setoolsgui.apol'], scripts=['apol', 'sediff', 'seinfo', 'seinfoflow', 'sesearch', 'sedta'], data_files=[(join(sys.prefix, 'share/man/man1'), glob.glob("man/*.1"))], package_data={'': ['*.ui', '*.qhc', '*.qch'], 'setools': ['perm_map']}, ext_modules=ext_py_mods, test_suite='tests', license='GPLv2+, LGPLv2.1+', classifiers=[ 'Environment :: Console', 'Environment :: X11 Applications :: Qt', 'Intended Audience :: Information Technology', 'Topic :: Security', 'Topic :: Utilities', ], ) setools-4.1.1/tests/000077500000000000000000000000001314142262400143465ustar00rootroot00000000000000setools-4.1.1/tests/__init__.py000066400000000000000000000025331314142262400164620ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from . import boolquery from . import boundsquery from . import categoryquery from . import constraintquery from . import commonquery from . import defaultquery from . import diff from . import dta from . import fsusequery from . import genfsconquery from . import infoflow from . import initsidquery from . import mlsrulequery from . import netifconquery from . import nodeconquery from . import objclassquery from . import permmap from . import polcapquery from . import policyrep from . import rbacrulequery from . import rolequery from . import sensitivityquery from . import terulequery from . import typeattrquery from . import typequery from . import userquery setools-4.1.1/tests/boolquery.conf000066400000000000000000000043171314142262400172430ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Booleans Query # # test 1 # name: test1 # default: unset bool test1 true; # test 2 # name: test2(a|b) regex # default: unset bool test2a true; bool test2b true; # test 10 # name: unset # default: false; bool test10a false; bool test10b false; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/boolquery.py000066400000000000000000000036351314142262400167500ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, BoolQuery class BoolQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/boolquery.conf") def test_000_unset(self): """Boolean query with no criteria.""" # query with no parameters gets all Booleans. allbools = sorted(str(b) for b in self.p.bools()) q = BoolQuery(self.p) qbools = sorted(str(b) for b in q.results()) self.assertListEqual(allbools, qbools) def test_001_name_exact(self): """Boolean query with exact match""" q = BoolQuery(self.p, name="test1") bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test1"], bools) def test_002_name_regex(self): """Boolean query with regex match.""" q = BoolQuery(self.p, name="test2(a|b)", name_regex=True) bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test2a", "test2b"], bools) def test_010_default(self): """Boolean query with default state match.""" q = BoolQuery(self.p, default=False) bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test10a", "test10b"], bools) setools-4.1.1/tests/boundsquery.conf000066400000000000000000000047671314142262400176130ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules # test 1 exact match parent type test1_parent; type test1_child; typebounds test1_parent test1_child; # test 2 regex match parent type test2_parent1; type test2_parent2; type test2_child1; type test2_child2; typebounds test2_parent1 test2_child2; typebounds test2_parent2 test2_child1; # test 10 exact match child type test10_parent; type test10_child; typebounds test10_parent test10_child; # test 11 regex match child type test11_parent1; type test11_parent2; type test11_child1; type test11_child2; typebounds test11_parent1 test11_child2; typebounds test11_parent2 test11_child1; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/boundsquery.py000066400000000000000000000063541314142262400173100ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, BoundsQuery, BoundsRuletype class BoundsQueryTest(unittest.TestCase): def setUp(self): self.p = SELinuxPolicy("tests/boundsquery.conf") def test_000_unset(self): """Bounds query with no criteria.""" # query with no parameters gets all bounds. allbounds = sorted(self.p.bounds()) q = BoundsQuery(self.p) qbounds = sorted(q.results()) self.assertListEqual(allbounds, qbounds) def test_001_parent_exact(self): """Bounds query with exact parent match.""" q = BoundsQuery(self.p, parent="test1_parent", parent_regex=False) qbounds = sorted(q.results()) self.assertEqual(1, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test1_parent", b.parent) self.assertEqual("test1_child", b.child) def test_002_parent_regex(self): """Bounds query with regex parent match.""" q = BoundsQuery(self.p, parent="test2_parent?", parent_regex=True) qbounds = sorted(q.results()) self.assertEqual(2, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test2_parent1", b.parent) self.assertEqual("test2_child2", b.child) b = qbounds[1] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test2_parent2", b.parent) self.assertEqual("test2_child1", b.child) def test_010_child_exact(self): """Bounds query with exact child match.""" q = BoundsQuery(self.p, child="test10_child", child_regex=False) qbounds = sorted(q.results()) self.assertEqual(1, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test10_parent", b.parent) self.assertEqual("test10_child", b.child) def test_011_child_regex(self): """Bounds query with regex child match.""" q = BoundsQuery(self.p, child="test11_child?", child_regex=True) qbounds = sorted(q.results()) self.assertEqual(2, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test11_parent1", b.parent) self.assertEqual("test11_child2", b.child) b = qbounds[1] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test11_parent2", b.parent) self.assertEqual("test11_child1", b.child) setools-4.1.1/tests/categoryquery.conf000066400000000000000000000043041314142262400201210ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity sens; dominance { sens } category begin; # test1 # name: test1 # alias: unset category test1; # test2 # name: test2(a|b) # alias: unset category test2a; category test2b; # test 10 # name: unset # alias: test10a category test10c1 alias { test10a test10c }; category test10c2 alias { test10b test10d }; # test 11 # name: unset # alias: test11(a|b) category test11c1 alias { test11a test11c }; category test11c2 alias { test11b test11d }; category test11c3 alias { test11e test11f }; category end; #level decl level sens:begin.end; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles system level sens range sens - sens:begin.end; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:sens:begin sid security system:system:system:sens:begin #fs_use fs_use_trans devpts system:object_r:system:sens; fs_use_xattr ext3 system:object_r:system:sens; fs_use_task pipefs system:object_r:system:sens; #genfscon genfscon proc / system:object_r:system:sens genfscon proc /sys system:object_r:system:sens genfscon selinuxfs / system:object_r:system:sens:begin.end portcon tcp 80 system:object_r:system:sens netifcon eth0 system:object_r:system:sens system:object_r:system:sens nodecon 127.0.0.1 255.255.255.255 system:object_r:system:sens:begin nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:sens:begin setools-4.1.1/tests/categoryquery.py000066400000000000000000000043471314142262400176330ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, CategoryQuery class CategoryQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/categoryquery.conf") def test_000_unset(self): """MLS category query with no criteria.""" # query with no parameters gets all categories. allcats = sorted(str(c) for c in self.p.categories()) q = CategoryQuery(self.p) qcats = sorted(str(c) for c in q.results()) self.assertListEqual(allcats, qcats) def test_001_name_exact(self): """MLS category query with exact name match.""" q = CategoryQuery(self.p, name="test1") cats = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], cats) def test_002_name_regex(self): """MLS category query with regex name match.""" q = CategoryQuery(self.p, name="test2(a|b)", name_regex=True) cats = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], cats) def test_010_alias_exact(self): """MLS category query with exact alias match.""" q = CategoryQuery(self.p, alias="test10a") cats = sorted(str(t) for t in q.results()) self.assertListEqual(["test10c1"], cats) def test_011_alias_regex(self): """MLS category query with regex alias match.""" q = CategoryQuery(self.p, alias="test11(a|b)", alias_regex=True) cats = sorted(str(t) for t in q.results()) self.assertListEqual(["test11c1", "test11c2"], cats) setools-4.1.1/tests/commonquery.conf000066400000000000000000000032131314142262400175720ustar00rootroot00000000000000class infoflow sid kernel sid security common test1 { hi_w hi_r super_r super_w } common test2a { send recv } common test2b { sig } common test10a { null } common test10b { null ping } common test11a { read write } common test11b { read } common test11c { write } common test12a { signal sigchld } common test12b { sigkill } class infoflow inherits test1 sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/commonquery.py000066400000000000000000000050321314142262400172760ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, CommonQuery class CommonQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/commonquery.conf") def test_000_unset(self): """Common query with no criteria.""" # query with no parameters gets all types. commons = sorted(self.p.commons()) q = CommonQuery(self.p) q_commons = sorted(q.results()) self.assertListEqual(commons, q_commons) def test_001_name_exact(self): """Common query with exact name match.""" q = CommonQuery(self.p, name="test1") commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], commons) def test_002_name_regex(self): """Common query with regex name match.""" q = CommonQuery(self.p, name="test2(a|b)", name_regex=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], commons) def test_010_perm_indirect_intersect(self): """Common query with intersect permission name patch.""" q = CommonQuery(self.p, perms=set(["null"]), perms_equal=False) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test10a", "test10b"], commons) def test_011_perm_indirect_equal(self): """Common query with equal permission name patch.""" q = CommonQuery(self.p, perms=set(["read", "write"]), perms_equal=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test11a"], commons) def test_012_perm_indirect_regex(self): """Common query with regex permission name patch.""" q = CommonQuery(self.p, perms="sig.+", perms_regex=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test12a", "test12b"], commons) setools-4.1.1/tests/constraintquery.conf000066400000000000000000000114341314142262400204720ustar00rootroot00000000000000class test1 class test10 class test11a class test11b class test11c class test12a class test12b class test12c class test20a class test20b class test20c class test21a class test21b class test21c class test30 class test31a class test31b class test40 class test41a class test41b class test50 class test51a class test51b sid kernel sid security common test { low_w med_w hi_w low_r med_r hi_r } class test1 inherits test class test10 inherits test class test11a inherits test class test11b inherits test class test11c inherits test class test12a inherits test class test12b inherits test class test12c inherits test class test20a { test20ap test20bp } class test20b { test20ap test20bp } class test20c { test20ap test20bp } class test21a { test21ap test21bp } class test21b { test21ap test21bp } class test21c { test21ap test21bp } class test30 inherits test class test31a inherits test class test31b inherits test class test40 inherits test class test41a inherits test class test41b inherits test class test50 inherits test class test51a inherits test class test51b inherits test sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; # test 1: # ruletype: mlsconstrain # tclass: unset # perms: unset mlsconstrain test1 hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role test30r; role test30r types system; role test31ra; role test31ra types system; role test31rb; role test31rb types system; type test40t; type test41ta; type test41tb; user system roles system level med range low_s - high_s:here.lost; user test50u roles system level med range low_s - high_s:here.lost; user test51u1 roles system level med range low_s - high_s:here.lost; user test51u2 roles system level med range low_s - high_s:here.lost; # test 10: # ruletype: unset # tclass: test10 # perms: unset # role: unset # type: unset # user: unset constrain test10 hi_w (u1 == u2); # test 11: # ruletype: unset # tclass: test11a, test11b # perms: unset # role: unset # type: unset # user: unset constrain test11a hi_w (u1 == u2); constrain test11b hi_w (u1 == u2); constrain test11c hi_w (u1 == u2); # test 12: # ruletype: unset # tclass: intoflow12(a|c), regex # perms: unset # role: unset # type: unset # user: unset constrain test12a hi_w (u1 == u2); constrain test12b hi_w (u1 == u2); constrain test12c hi_w (u1 == u2); # test 20: # ruletype: unset # tclass: unset # perms: test20ap, test20bp # role: unset # type: unset # user: unset constrain test20a test20ap (u1 == u2); constrain test20b test20bp (u1 == u2); # test 21: # ruletype: unset # tclass: unset # perms: test21ap, test21bp, equal # role: unset # type: unset # user: unset constrain test21a test21ap (u1 == u2); constrain test21b test21bp (u1 == u2); constrain test21c { test21bp test21ap } (u1 == u2); # test 30: # ruletype: unset # tclass: unset # perms: unset # role: test30r # type: unset # user: unset constrain test30 hi_w (u1 == u2 or r1 == test30r); # test 31: # ruletype: unset # tclass: unset # perms: unset # role: test31r. regex # type: unset # user: unset constrain test31a hi_w (u1 == u2 or r1 == test31ra); validatetrans test31b (u1 == u2 or r2 == test31rb); # test 40: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: test40 # user: unset constrain test40 hi_w (u1 == u2 or t1 == test40t); # test 41: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: test41. regex # user: unset constrain test41a hi_w (u1 == u2 or t1 == test41ta); constrain test41b hi_w (u1 == u2 or t2 == test41tb); # test 50: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: unset # user: test50 constrain test50 hi_w (u1 == u2 or u1 == test50u); # test 51: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: unset # user: test51u. regex constrain test51a hi_w (u1 == u2 or u1 == test51u1); constrain test51b hi_w (u1 == u2 or u2 == test51u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/constraintquery.py000066400000000000000000000110631314142262400201730ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, ConstraintQuery class ConstraintQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/constraintquery.conf") def test_000_unset(self): """Constraint query with no criteria.""" allconstraint = sorted(c.tclass for c in self.p.constraints()) q = ConstraintQuery(self.p) qconstraint = sorted(c.tclass for c in q.results()) self.assertListEqual(allconstraint, qconstraint) def test_001_ruletype(self): """Constraint query with rule type match.""" q = ConstraintQuery(self.p, ruletype=["mlsconstrain"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test1"], constraint) @unittest.skip("Setting tclass to a string is no longer supported.") def test_010_class_exact(self): """Constraint query with exact object class match.""" q = ConstraintQuery(self.p, tclass="test10") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test10"], constraint) def test_011_class_list(self): """Constraint query with object class list match.""" q = ConstraintQuery(self.p, tclass=["test11a", "test11b"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test11a", "test11b"], constraint) def test_012_class_regex(self): """Constraint query with object class regex match.""" q = ConstraintQuery(self.p, tclass="test12(a|c)", tclass_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test12a", "test12c"], constraint) def test_020_perms_any(self): """Constraint query with permission set intersection match.""" q = ConstraintQuery(self.p, perms=["test20ap", "test20bp"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test20a", "test20b"], constraint) def test_021_perms_equal(self): """Constraint query with permission set equality match.""" q = ConstraintQuery(self.p, perms=["test21ap", "test21bp"], perms_equal=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test21c"], constraint) def test_030_role_match_single(self): """Constraint query with role match.""" q = ConstraintQuery(self.p, role="test30r") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test30"], constraint) def test_031_role_match_regex(self): """Constraint query with regex role match.""" q = ConstraintQuery(self.p, role="test31r.", role_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test31a", "test31b"], constraint) def test_040_type_match_single(self): """Constraint query with type match.""" q = ConstraintQuery(self.p, type_="test40t") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test40"], constraint) def test_041_type_match_regex(self): """Constraint query with regex type match.""" q = ConstraintQuery(self.p, type_="test41t.", type_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test41a", "test41b"], constraint) def test_050_user_match_single(self): """Constraint query with user match.""" q = ConstraintQuery(self.p, user="test50u") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test50"], constraint) def test_051_user_match_regex(self): """Constraint query with regex user match.""" q = ConstraintQuery(self.p, user="test51u.", user_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test51a", "test51b"], constraint) setools-4.1.1/tests/defaultquery.conf000066400000000000000000000043131314142262400177300ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } ######################################## # # Default settings # default_user infoflow target; default_role { infoflow infoflow3 } source; default_type infoflow4 target; default_range infoflow5 target low; default_range infoflow7 target high; ######################################### sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/defaultquery.py000066400000000000000000000067741314142262400174500ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, DefaultQuery, DefaultRuletype, DefaultValue from setools.policyrep.exception import InvalidClass class DefaultQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/defaultquery.conf") def test_000_unset(self): """Default query: no criteria.""" # query with no parameters gets all defaults alldefaults = sorted(self.p.defaults()) q = DefaultQuery(self.p) qdefaults = sorted(q.results()) self.assertListEqual(alldefaults, qdefaults) def test_001_ruletype(self): """Default query: ruletype criterion.""" q = DefaultQuery(self.p, ruletype=["default_user"]) defaults = list(q.results()) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("infoflow", d.tclass) self.assertEqual(DefaultValue.target, d.default) def test_010_class_list(self): """Default query: object class list match.""" q = DefaultQuery(self.p, tclass=["infoflow3", "infoflow4"]) defaults = sorted(d.tclass for d in q.results()) self.assertListEqual(["infoflow3", "infoflow4"], defaults) def test_011_class_regex(self): """Default query: object class regex match.""" q = DefaultQuery(self.p, tclass="infoflow(3|5)", tclass_regex=True) defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow3", "infoflow5"], defaults) def test_020_default(self): """Default query: default setting.""" q = DefaultQuery(self.p, default="source") defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow", "infoflow3"], defaults) def test_030_default_range(self): """Default query: default_range setting.""" q = DefaultQuery(self.p, default_range="high") defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow7"], defaults) def test_900_invalid_ruletype(self): """Default query: invalid ruletype""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, ruletype=["INVALID"]) def test_901_invalid_class(self): """Default query: invalid object class""" with self.assertRaises(InvalidClass): q = DefaultQuery(self.p, tclass=["INVALID"]) def test_902_invalid_default_value(self): """Default query: invalid default value""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, default="INVALID") def test_903_invalid_default_range(self): """Default query: invalid default range""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, default_range="INVALID") setools-4.1.1/tests/devicetreeconquery.conf000066400000000000000000000100451314142262400211220ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # irq: unset # user: unset # role: unset # type: unset # range: unset devicetreecon "/dev/tree1" system:system:system:s0:c0.c1 # test 10: # irq: unset # user: user10, exact # role: unset # type: unset # range: unset devicetreecon "/dev/tree10" user10:system:system:s0:c0.c1 # test 11: # irq: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset devicetreecon "/dev/tree11" user11a:system:system:s0:c0.c1 devicetreecon "/dev/tree11000" user11b:system:system:s0:c0.c1 devicetreecon "/dev/tree11001" user11c:system:system:s0:c0.c1 # test 20: # irq: unset # user: unset # role: role20_r, exact # type: unset # range: unset devicetreecon "/dev/tree20" system:role20_r:system:s0:c0.c1 # test 21: # irq: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset devicetreecon "/dev/tree21" system:role21a_r:system:s0:c0.c1 devicetreecon "/dev/tree21000" system:role21b_r:system:s0:c0.c1 devicetreecon "/dev/tree21001" system:role21c_r:system:s0:c0.c1 # test 30: # irq: unset # user: unset # role: unset # type: type30 # range: unset devicetreecon "/dev/tree30" system:system:type30:s0:c0.c1 # test 31: # irq: unset # user: unset # role: unset # type: type31(b|c) # range: unset devicetreecon "/dev/tree31" system:system:type31a:s0:c0.c1 devicetreecon "/dev/tree31000" system:system:type31b:s0:c0.c1 devicetreecon "/dev/tree31001" system:system:type31c:s0:c0.c1 # test 40: # irq: unset # user: unset # role: unset # type: unset # range: equal devicetreecon "/dev/tree40" system:system:system:s0:c1 - s0:c0.c4 # test 41: # irq: unset # user: unset # role: unset # type: unset # range: overlap devicetreecon "/dev/tree41" system:system:system:s1:c1 - s1:c1.c3 # test 42: # irq: unset # user: unset # role: unset # type: unset # range: subset devicetreecon "/dev/tree42" system:system:system:s2:c1 - s2:c1.c3 # test 43: # irq: unset # user: unset # role: unset # type: unset # range: superset devicetreecon "/dev/tree43" system:system:system:s3:c1 - s3:c1.c3 # test 44: # irq: unset # user: unset # role: unset # type: unset # range: proper subset devicetreecon "/dev/tree44" system:system:system:s4:c1 - s4:c1.c3 # test 45: # irq: unset # user: unset # role: unset # type: unset # range: proper superset devicetreecon "/dev/tree45" system:system:system:s5:c1 - s5:c1.c3 setools-4.1.1/tests/devicetreeconquery.py000066400000000000000000000213541314142262400206320ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, DevicetreeconQuery class DevicetreeconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/devicetreeconquery.conf") def test_000_unset(self): """Devicetreecon query with no criteria""" # query with no parameters gets all PCI paths. rules = sorted(self.p.devicetreecons()) q = DevicetreeconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Devicetreecon query with context user exact match""" q = DevicetreeconQuery(self.p, user="user10", user_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree10")], path) def test_011_user_regex(self): """Devicetreecon query with context user regex match""" q = DevicetreeconQuery(self.p, user="user11(a|b)", user_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree11"), ("/dev/tree11000")], path) def test_020_role_exact(self): """Devicetreecon query with context role exact match""" q = DevicetreeconQuery(self.p, role="role20_r", role_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree20")], path) def test_021_role_regex(self): """Devicetreecon query with context role regex match""" q = DevicetreeconQuery(self.p, role="role21(a|c)_r", role_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree21"), ("/dev/tree21001")], path) def test_030_type_exact(self): """Devicetreecon query with context type exact match""" q = DevicetreeconQuery(self.p, type_="type30", type_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree30")], path) def test_031_type_regex(self): """Devicetreecon query with context type regex match""" q = DevicetreeconQuery(self.p, type_="type31(b|c)", type_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree31000"), ("/dev/tree31001")], path) def test_040_range_exact(self): """Devicetreecon query with context range exact match""" q = DevicetreeconQuery(self.p, range_="s0:c1 - s0:c0.c4") path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree40")], path) def test_041_range_overlap1(self): """Devicetreecon query with context range overlap match (equal)""" q = DevicetreeconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap2(self): """Devicetreecon query with context range overlap match (subset)""" q = DevicetreeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap3(self): """Devicetreecon query with context range overlap match (superset)""" q = DevicetreeconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap4(self): """Devicetreecon query with context range overlap match (overlap low level)""" q = DevicetreeconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap5(self): """Devicetreecon query with context range overlap match (overlap high level)""" q = DevicetreeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_042_range_subset1(self): """Devicetreecon query with context range subset match""" q = DevicetreeconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree42")], path) def test_042_range_subset2(self): """Devicetreecon query with context range subset match (equal)""" q = DevicetreeconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree42")], path) def test_043_range_superset1(self): """Devicetreecon query with context range superset match""" q = DevicetreeconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree43")], path) def test_043_range_superset2(self): """Devicetreecon query with context range superset match (equal)""" q = DevicetreeconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree43")], path) def test_044_range_proper_subset1(self): """Devicetreecon query with context range proper subset match""" q = DevicetreeconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_044_range_proper_subset2(self): """Devicetreecon query with context range proper subset match (equal)""" q = DevicetreeconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([], path) def test_044_range_proper_subset3(self): """Devicetreecon query with context range proper subset match (equal low only)""" q = DevicetreeconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_044_range_proper_subset4(self): """Devicetreecon query with context range proper subset match (equal high only)""" q = DevicetreeconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_045_range_proper_superset1(self): """Devicetreecon query with context range proper superset match""" q = DevicetreeconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) def test_045_range_proper_superset2(self): """Devicetreecon query with context range proper superset match (equal)""" q = DevicetreeconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([], path) def test_045_range_proper_superset3(self): """Devicetreecon query with context range proper superset match (equal low)""" q = DevicetreeconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) def test_045_range_proper_superset4(self): """Devicetreecon query with context range proper superset match (equal high)""" q = DevicetreeconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) setools-4.1.1/tests/diff.py000066400000000000000000003357621314142262400156500ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from socket import IPPROTO_TCP, IPPROTO_UDP from setools import SELinuxPolicy, PolicyDifference from setools import BoundsRuletype as BRT from setools import ConstraintRuletype as CRT from setools import DefaultRuletype as DRT from setools import DefaultRangeValue as DRV from setools import DefaultValue as DV from setools import FSUseRuletype as FSURT from setools import MLSRuletype as MRT from setools import RBACRuletype as RRT from setools import TERuletype as TRT from .mixins import ValidateRule class PolicyDifferenceTest(ValidateRule, unittest.TestCase): """Policy difference tests.""" @classmethod def setUpClass(cls): cls.diff = PolicyDifference(SELinuxPolicy("tests/diff_left.conf"), SELinuxPolicy("tests/diff_right.conf")) # # Types # def test_added_types(self): """Diff: added type""" self.assertSetEqual(set(["added_type"]), self.diff.added_types) def test_removed_types(self): """Diff: modified type""" self.assertSetEqual(set(["removed_type"]), self.diff.removed_types) def test_modified_types_count(self): """Diff: total modified types""" self.assertEqual(6, len(self.diff.modified_types)) def test_modified_types_remove_attr(self): """Diff: modified type with removed attribute.""" self.assertIn("modified_remove_attr", self.diff.modified_types) removed_attrs = self.diff.modified_types["modified_remove_attr"].removed_attributes self.assertSetEqual(set(["an_attr"]), removed_attrs) self.assertFalse(self.diff.modified_types["modified_remove_attr"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_attr"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_remove_attr"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_remove_attr"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_attr"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_attr"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_remove_attr"].matched_aliases) def test_modified_types_remove_alias(self): """Diff: modified type with removed alias.""" self.assertIn("modified_remove_alias", self.diff.modified_types) removed_alias = self.diff.modified_types["modified_remove_alias"].removed_aliases self.assertSetEqual(set(["an_alias"]), removed_alias) self.assertFalse(self.diff.modified_types["modified_remove_alias"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_remove_alias"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_alias"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_alias"].matched_aliases) def test_modified_types_remove_permissive(self): """Diff: modified type with removed permissve.""" self.assertIn("modified_remove_permissive", self.diff.modified_types) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].matched_attributes) self.assertTrue(self.diff.modified_types["modified_remove_permissive"].modified_permissive) self.assertTrue(self.diff.modified_types["modified_remove_permissive"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].matched_aliases) def test_modified_types_add_attr(self): """Diff: modified type with added attribute.""" self.assertIn("modified_add_attr", self.diff.modified_types) added_attrs = self.diff.modified_types["modified_add_attr"].added_attributes self.assertSetEqual(set(["an_attr"]), added_attrs) self.assertFalse(self.diff.modified_types["modified_add_attr"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_attr"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_add_attr"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_attr"].permissive) self.assertFalse(self.diff.modified_types["modified_add_attr"].added_aliases) self.assertFalse(self.diff.modified_types["modified_add_attr"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_attr"].matched_aliases) def test_modified_types_add_alias(self): """Diff: modified type with added alias.""" self.assertIn("modified_add_alias", self.diff.modified_types) added_alias = self.diff.modified_types["modified_add_alias"].added_aliases self.assertSetEqual(set(["an_alias"]), added_alias) self.assertFalse(self.diff.modified_types["modified_add_alias"].added_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_alias"].permissive) self.assertFalse(self.diff.modified_types["modified_add_alias"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_alias"].matched_aliases) def test_modified_types_add_permissive(self): """Diff: modified type with added permissive.""" self.assertIn("modified_add_permissive", self.diff.modified_types) self.assertFalse(self.diff.modified_types["modified_add_permissive"].added_attributes) self.assertFalse(self.diff.modified_types["modified_add_permissive"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_permissive"].matched_attributes) self.assertTrue(self.diff.modified_types["modified_add_permissive"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_permissive"].permissive) self.assertFalse(self.diff.modified_types["modified_add_permissive"].added_aliases) self.assertFalse(self.diff.modified_types["modified_add_permissive"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_permissive"].matched_aliases) # # Roles # def test_added_role(self): """Diff: added role.""" self.assertSetEqual(set(["added_role"]), self.diff.added_roles) def test_removed_role(self): """Diff: removed role.""" self.assertSetEqual(set(["removed_role"]), self.diff.removed_roles) def test_modified_role_count(self): """Diff: modified role.""" self.assertEqual(2, len(self.diff.modified_roles)) def test_modified_role_add_type(self): """Diff: modified role with added type.""" self.assertSetEqual(set(["system"]), self.diff.modified_roles["modified_add_type"].added_types) self.assertFalse(self.diff.modified_roles["modified_add_type"].removed_types) def test_modified_role_remove_type(self): """Diff: modified role with removed type.""" self.assertSetEqual(set(["system"]), self.diff.modified_roles["modified_remove_type"].removed_types) self.assertFalse(self.diff.modified_roles["modified_remove_type"].added_types) # # Commons # def test_added_common(self): """Diff: added common.""" self.assertSetEqual(set(["added_common"]), self.diff.added_commons) def test_removed_common(self): """Diff: removed common.""" self.assertSetEqual(set(["removed_common"]), self.diff.removed_commons) def test_modified_common_count(self): """Diff: modified common count.""" self.assertEqual(2, len(self.diff.modified_commons)) def test_modified_common_add_perm(self): """Diff: modified common with added perm.""" self.assertSetEqual(set(["added_perm"]), self.diff.modified_commons["modified_add_perm"].added_perms) self.assertFalse(self.diff.modified_commons["modified_add_perm"].removed_perms) def test_modified_common_remove_perm(self): """Diff: modified common with removed perm.""" self.assertSetEqual(set(["removed_perm"]), self.diff.modified_commons["modified_remove_perm"].removed_perms) self.assertFalse(self.diff.modified_commons["modified_remove_perm"].added_perms) # # Classes # def test_added_class(self): """Diff: added class.""" self.assertSetEqual(set(["added_class"]), self.diff.added_classes) def test_removed_class(self): """Diff: removed class.""" self.assertSetEqual(set(["removed_class"]), self.diff.removed_classes) def test_modified_class_count(self): """Diff: modified class count.""" self.assertEqual(3, len(self.diff.modified_classes)) def test_modified_class_add_perm(self): """Diff: modified class with added perm.""" self.assertSetEqual(set(["added_perm"]), self.diff.modified_classes["modified_add_perm"].added_perms) self.assertFalse(self.diff.modified_classes["modified_add_perm"].removed_perms) def test_modified_class_remove_perm(self): """Diff: modified class with removed perm.""" self.assertSetEqual(set(["removed_perm"]), self.diff.modified_classes["modified_remove_perm"].removed_perms) self.assertFalse(self.diff.modified_classes["modified_remove_perm"].added_perms) def test_modified_class_change_common(self): """Diff: modified class due to modified common.""" self.assertSetEqual(set(["old_com"]), self.diff.modified_classes["modified_change_common"].removed_perms) self.assertSetEqual(set(["new_com"]), self.diff.modified_classes["modified_change_common"].added_perms) # # Allow rules # def test_added_allow_rules(self): """Diff: added allow rules.""" rules = sorted(self.diff.added_allows) self.assertEqual(5, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.allow, "added_rule_source", "added_rule_target", "infoflow", set(["med_w"])) # added rule with new type self.validate_rule(rules[1], TRT.allow, "added_type", "added_type", "infoflow2", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[2], TRT.allow, "move_from_bool", "move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[3], TRT.allow, "move_to_bool", "move_to_bool", "infoflow4", set(["hi_w"]), cond="move_to_bool_b", cond_block=True) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.allow, "system", "switch_block", "infoflow6", set(["hi_r"]), cond="switch_block_b", cond_block=False) def test_removed_allow_rules(self): """Diff: removed allow rules.""" rules = sorted(self.diff.removed_allows) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.allow, "move_from_bool", "move_from_bool", "infoflow4", set(["hi_r"]), cond="move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.allow, "move_to_bool", "move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.allow, "removed_rule_source", "removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.allow, "removed_type", "removed_type", "infoflow3", set(["null"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.allow, "system", "switch_block", "infoflow6", set(["hi_r"]), cond="switch_block_b", cond_block=True) def test_modified_allow_rules(self): """Diff: modified allow rules.""" l = sorted(self.diff.modified_allows, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_add_perms", rule.source) self.assertEqual("modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_add_remove_perms", rule.source) self.assertEqual("modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_remove_perms", rule.source) self.assertEqual("modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Auditallow rules # def test_added_auditallow_rules(self): """Diff: added auditallow rules.""" rules = sorted(self.diff.added_auditallows) self.assertEqual(5, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.auditallow, "aa_added_rule_source", "aa_added_rule_target", "infoflow", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[1], TRT.auditallow, "aa_move_from_bool", "aa_move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[2], TRT.auditallow, "aa_move_to_bool", "aa_move_to_bool", "infoflow4", set(["hi_w"]), cond="aa_move_to_bool_b", cond_block=True) # added rule with new type self.validate_rule(rules[3], TRT.auditallow, "added_type", "added_type", "infoflow7", set(["super_none"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.auditallow, "system", "aa_switch_block", "infoflow6", set(["hi_r"]), cond="aa_switch_block_b", cond_block=False) def test_removed_auditallow_rules(self): """Diff: removed auditallow rules.""" rules = sorted(self.diff.removed_auditallows) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.auditallow, "aa_move_from_bool", "aa_move_from_bool", "infoflow4", set(["hi_r"]), cond="aa_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.auditallow, "aa_move_to_bool", "aa_move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.auditallow, "aa_removed_rule_source", "aa_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.auditallow, "removed_type", "removed_type", "infoflow7", set(["super_unmapped"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.auditallow, "system", "aa_switch_block", "infoflow6", set(["hi_r"]), cond="aa_switch_block_b", cond_block=True) def test_modified_auditallow_rules(self): """Diff: modified auditallow rules.""" l = sorted(self.diff.modified_auditallows, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_add_perms", rule.source) self.assertEqual("aa_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_add_remove_perms", rule.source) self.assertEqual("aa_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_remove_perms", rule.source) self.assertEqual("aa_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Dontaudit rules # def test_added_dontaudit_rules(self): """Diff: added dontaudit rules.""" rules = sorted(self.diff.added_dontaudits) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.dontaudit, "added_type", "added_type", "infoflow7", set(["super_none"])) # added rule with existing types self.validate_rule(rules[1], TRT.dontaudit, "da_added_rule_source", "da_added_rule_target", "infoflow", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[2], TRT.dontaudit, "da_move_from_bool", "da_move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[3], TRT.dontaudit, "da_move_to_bool", "da_move_to_bool", "infoflow4", set(["hi_w"]), cond="da_move_to_bool_b", cond_block=True) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.dontaudit, "system", "da_switch_block", "infoflow6", set(["hi_r"]), cond="da_switch_block_b", cond_block=False) def test_removed_dontaudit_rules(self): """Diff: removed dontaudit rules.""" rules = sorted(self.diff.removed_dontaudits) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.dontaudit, "da_move_from_bool", "da_move_from_bool", "infoflow4", set(["hi_r"]), cond="da_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.dontaudit, "da_move_to_bool", "da_move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.dontaudit, "da_removed_rule_source", "da_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.dontaudit, "removed_type", "removed_type", "infoflow7", set(["super_both"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.dontaudit, "system", "da_switch_block", "infoflow6", set(["hi_r"]), cond="da_switch_block_b", cond_block=True) def test_modified_dontaudit_rules(self): """Diff: modified dontaudit rules.""" l = sorted(self.diff.modified_dontaudits, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_add_perms", rule.source) self.assertEqual("da_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_add_remove_perms", rule.source) self.assertEqual("da_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_remove_perms", rule.source) self.assertEqual("da_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Neverallow rules # def test_added_neverallow_rules(self): """Diff: added neverallow rules.""" rules = sorted(self.diff.added_neverallows) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.neverallow, "added_type", "added_type", "added_class", set(["new_class_perm"])) # added rule with existing types self.validate_rule(rules[1], TRT.neverallow, "na_added_rule_source", "na_added_rule_target", "infoflow", set(["med_w"])) def test_removed_neverallow_rules(self): """Diff: removed neverallow rules.""" rules = sorted(self.diff.removed_neverallows) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.neverallow, "na_removed_rule_source", "na_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[1], TRT.neverallow, "removed_type", "removed_type", "removed_class", set(["null_perm"])) def test_modified_neverallow_rules(self): """Diff: modified neverallow rules.""" l = sorted(self.diff.modified_neverallows, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.neverallow, rule.ruletype) self.assertEqual("na_modified_rule_add_perms", rule.source) self.assertEqual("na_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.neverallow, rule.ruletype) self.assertEqual("na_modified_rule_add_remove_perms", rule.source) self.assertEqual("na_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.neverallow, rule.ruletype) self.assertEqual("na_modified_rule_remove_perms", rule.source) self.assertEqual("na_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Type_transition rules # def test_added_type_transition_rules(self): """Diff: added type_transition rules.""" rules = sorted(self.diff.added_type_transitions) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_transition, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_transition, "system", "tt_switch_block", "infoflow6", "system", cond="tt_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_transition, "tt_added_rule_source", "tt_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_transition, "tt_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_transition, "tt_move_to_bool", "system", "infoflow3", "system", cond="tt_move_to_bool_b", cond_block=True) def test_removed_type_transition_rules(self): """Diff: removed type_transition rules.""" rules = sorted(self.diff.removed_type_transitions) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_transition, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_transition, "system", "tt_switch_block", "infoflow6", "system", cond="tt_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_transition, "tt_move_from_bool", "system", "infoflow4", "system", cond="tt_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_transition, "tt_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_transition, "tt_removed_rule_source", "tt_removed_rule_target", "infoflow", "system") def test_modified_type_transition_rules(self): """Diff: modified type_transition rules.""" l = sorted(self.diff.modified_type_transitions, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_default, removed_default = l[0] self.assertEqual(TRT.type_transition, rule.ruletype) self.assertEqual("tt_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tt_new_type", added_default) self.assertEqual("tt_old_type", removed_default) # # Type_change rules # def test_added_type_change_rules(self): """Diff: added type_change rules.""" rules = sorted(self.diff.added_type_changes) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_change, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_change, "system", "tc_switch_block", "infoflow6", "system", cond="tc_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_change, "tc_added_rule_source", "tc_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_change, "tc_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_change, "tc_move_to_bool", "system", "infoflow3", "system", cond="tc_move_to_bool_b", cond_block=True) def test_removed_type_change_rules(self): """Diff: removed type_change rules.""" rules = sorted(self.diff.removed_type_changes) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_change, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_change, "system", "tc_switch_block", "infoflow6", "system", cond="tc_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_change, "tc_move_from_bool", "system", "infoflow4", "system", cond="tc_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_change, "tc_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_change, "tc_removed_rule_source", "tc_removed_rule_target", "infoflow", "system") def test_modified_type_change_rules(self): """Diff: modified type_change rules.""" l = sorted(self.diff.modified_type_changes, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_default, removed_default = l[0] self.assertEqual(TRT.type_change, rule.ruletype) self.assertEqual("tc_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tc_new_type", added_default) self.assertEqual("tc_old_type", removed_default) # # Type_member rules # def test_added_type_member_rules(self): """Diff: added type_member rules.""" rules = sorted(self.diff.added_type_members) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_member, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_member, "system", "tm_switch_block", "infoflow6", "system", cond="tm_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_member, "tm_added_rule_source", "tm_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_member, "tm_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_member, "tm_move_to_bool", "system", "infoflow3", "system", cond="tm_move_to_bool_b", cond_block=True) def test_removed_type_member_rules(self): """Diff: removed type_member rules.""" rules = sorted(self.diff.removed_type_members) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_member, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_member, "system", "tm_switch_block", "infoflow6", "system", cond="tm_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_member, "tm_move_from_bool", "system", "infoflow4", "system", cond="tm_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_member, "tm_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_member, "tm_removed_rule_source", "tm_removed_rule_target", "infoflow", "system") def test_modified_type_member_rules(self): """Diff: modified type_member rules.""" l = sorted(self.diff.modified_type_members, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_default, removed_default = l[0] self.assertEqual(TRT.type_member, rule.ruletype) self.assertEqual("tm_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tm_new_type", added_default) self.assertEqual("tm_old_type", removed_default) # # Range_transition rules # def test_added_range_transition_rules(self): """Diff: added range_transition rules.""" rules = sorted(self.diff.added_range_transitions) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], MRT.range_transition, "added_type", "system", "infoflow4", "s3") # added rule with existing types self.validate_rule(rules[1], MRT.range_transition, "rt_added_rule_source", "rt_added_rule_target", "infoflow", "s3") def test_removed_range_transition_rules(self): """Diff: removed range_transition rules.""" rules = sorted(self.diff.removed_range_transitions) self.assertEqual(2, len(rules)) # removed rule with new type self.validate_rule(rules[0], MRT.range_transition, "removed_type", "system", "infoflow4", "s1") # removed rule with existing types self.validate_rule(rules[1], MRT.range_transition, "rt_removed_rule_source", "rt_removed_rule_target", "infoflow", "s1") def test_modified_range_transition_rules(self): """Diff: modified range_transition rules.""" l = sorted(self.diff.modified_range_transitions, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_default, removed_default = l[0] self.assertEqual(MRT.range_transition, rule.ruletype) self.assertEqual("rt_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("s0:c0,c4 - s1:c0.c2,c4", added_default) self.assertEqual("s2:c0 - s3:c0.c2", removed_default) # # Role allow rules # def test_added_role_allow_rules(self): """Diff: added role_allow rules.""" rules = sorted(self.diff.added_role_allows) self.assertEqual(2, len(rules)) # added rule with existing roles self.assertEqual(RRT.allow, rules[0].ruletype) self.assertEqual("added_role", rules[0].source) self.assertEqual("system", rules[0].target) # added rule with new roles self.assertEqual(RRT.allow, rules[1].ruletype) self.assertEqual("added_rule_source_r", rules[1].source) self.assertEqual("added_rule_target_r", rules[1].target) def test_removed_role_allow_rules(self): """Diff: removed role_allow rules.""" rules = sorted(self.diff.removed_role_allows) self.assertEqual(2, len(rules)) # removed rule with removed role self.assertEqual(RRT.allow, rules[0].ruletype) self.assertEqual("removed_role", rules[0].source) self.assertEqual("system", rules[0].target) # removed rule with existing roles self.assertEqual(RRT.allow, rules[1].ruletype) self.assertEqual("removed_rule_source_r", rules[1].source) self.assertEqual("removed_rule_target_r", rules[1].target) # # Role_transition rules # def test_added_role_transition_rules(self): """Diff: added role_transition rules.""" rules = sorted(self.diff.added_role_transitions) self.assertEqual(2, len(rules)) # added rule with new role self.validate_rule(rules[0], RRT.role_transition, "added_role", "system", "infoflow4", "system") # added rule with existing roles self.validate_rule(rules[1], RRT.role_transition, "role_tr_added_rule_source", "role_tr_added_rule_target", "infoflow6", "system") def test_removed_role_transition_rules(self): """Diff: removed role_transition rules.""" rules = sorted(self.diff.removed_role_transitions) self.assertEqual(2, len(rules)) # removed rule with new role self.validate_rule(rules[0], RRT.role_transition, "removed_role", "system", "infoflow4", "system") # removed rule with existing roles self.validate_rule(rules[1], RRT.role_transition, "role_tr_removed_rule_source", "role_tr_removed_rule_target", "infoflow5", "system") def test_modified_role_transition_rules(self): """Diff: modified role_transition rules.""" l = sorted(self.diff.modified_role_transitions, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_default, removed_default = l[0] self.assertEqual(RRT.role_transition, rule.ruletype) self.assertEqual("role_tr_matched_source", rule.source) self.assertEqual("role_tr_matched_target", rule.target) self.assertEqual("infoflow3", rule.tclass) self.assertEqual("role_tr_new_role", added_default) self.assertEqual("role_tr_old_role", removed_default) # # Users # def test_added_user(self): """Diff: added user.""" self.assertSetEqual(set(["added_user"]), self.diff.added_users) def test_removed_user(self): """Diff: removed user.""" self.assertSetEqual(set(["removed_user"]), self.diff.removed_users) def test_modified_user_count(self): """Diff: modified user count.""" self.assertEqual(4, len(self.diff.modified_users)) def test_modified_user_add_role(self): """Diff: modified user with added role.""" self.assertSetEqual(set(["added_role"]), self.diff.modified_users["modified_add_role"].added_roles) self.assertFalse(self.diff.modified_users["modified_add_role"].removed_roles) def test_modified_user_remove_role(self): """Diff: modified user with removed role.""" self.assertSetEqual(set(["removed_role"]), self.diff.modified_users["modified_remove_role"].removed_roles) self.assertFalse(self.diff.modified_users["modified_remove_role"].added_roles) def test_modified_user_change_level(self): """Diff: modified user due to modified default level.""" self.assertEqual("s2:c0", self.diff.modified_users["modified_change_level"].removed_level) self.assertEqual("s2:c1", self.diff.modified_users["modified_change_level"].added_level) def test_modified_user_change_range(self): """Diff: modified user due to modified range.""" self.assertEqual("s3:c1 - s3:c1.c3", self.diff.modified_users["modified_change_range"].removed_range) self.assertEqual("s3:c1 - s3:c1.c4", self.diff.modified_users["modified_change_range"].added_range) # # Type attributes # def test_added_type_attribute(self): """Diff: added type attribute.""" self.assertSetEqual(set(["added_attr"]), self.diff.added_type_attributes) def test_removed_type_attribute(self): """Diff: removed type attribute.""" self.assertSetEqual(set(["removed_attr"]), self.diff.removed_type_attributes) def test_modified_type_attribute(self): """Diff: modified type attribute.""" self.assertEqual(1, len(self.diff.modified_type_attributes)) self.assertSetEqual(set(["modified_add_attr"]), self.diff.modified_type_attributes["an_attr"].added_types) self.assertSetEqual(set(["modified_remove_attr"]), self.diff.modified_type_attributes["an_attr"].removed_types) # # Booleans # def test_added_boolean(self): """Diff: added boolean.""" self.assertSetEqual(set(["added_bool"]), self.diff.added_booleans) def test_removed_boolean(self): """Diff: removed boolean.""" self.assertSetEqual(set(["removed_bool"]), self.diff.removed_booleans) def test_modified_boolean(self): """Diff: modified boolean.""" self.assertEqual(1, len(self.diff.modified_booleans)) self.assertTrue(self.diff.modified_booleans["modified_bool"].added_state) self.assertFalse(self.diff.modified_booleans["modified_bool"].removed_state) # # Categories # def test_added_category(self): """Diff: added category.""" self.assertSetEqual(set(["c6"]), self.diff.added_categories) def test_removed_category(self): """Diff: removed category.""" self.assertSetEqual(set(["c5"]), self.diff.removed_categories) def test_modified_category(self): """Diff: modified categories.""" self.assertEqual(2, len(self.diff.modified_categories)) # add alias self.assertEqual(set(["foo"]), self.diff.modified_categories["c1"].added_aliases) self.assertFalse(self.diff.modified_categories["c1"].removed_aliases) # remove alias self.assertFalse(self.diff.modified_categories["c0"].added_aliases) self.assertEqual(set(["eggs"]), self.diff.modified_categories["c0"].removed_aliases) # # Sensitivity # def test_added_sensitivities(self): """Diff: added sensitivities.""" self.assertSetEqual(set(["s46"]), self.diff.added_sensitivities) def test_removed_sensitivities(self): """Diff: removed sensitivities.""" self.assertSetEqual(set(["s47"]), self.diff.removed_sensitivities) def test_modified_sensitivities(self): """Diff: modified sensitivities.""" self.assertEqual(2, len(self.diff.modified_sensitivities)) # add alias self.assertSetEqual(set(["al4"]), self.diff.modified_sensitivities["s1"].added_aliases) self.assertFalse(self.diff.modified_sensitivities["s1"].removed_aliases) # remove alias self.assertFalse(self.diff.modified_sensitivities["s0"].added_aliases) self.assertSetEqual(set(["al2"]), self.diff.modified_sensitivities["s0"].removed_aliases) # # Initial SIDs # def test_added_initialsids(self): """Diff: added initialsids.""" self.assertSetEqual(set(["added_sid"]), self.diff.added_initialsids) def test_removed_initialsids(self): """Diff: removed initialsids.""" self.assertSetEqual(set(["removed_sid"]), self.diff.removed_initialsids) def test_modified_initialsids(self): """Diff: modified initialsids.""" self.assertEqual(1, len(self.diff.modified_initialsids)) self.assertEqual("modified_add_role:system:system:s2", self.diff.modified_initialsids["modified_sid"].added_context) self.assertEqual("system:system:system:s0", self.diff.modified_initialsids["modified_sid"].removed_context) # # fs_use_* # def test_added_fs_uses(self): """Diff: added fs_uses.""" l = sorted(self.diff.added_fs_uses) self.assertEqual(1, len(l)) rule = l[0] self.assertEqual(FSURT.fs_use_xattr, rule.ruletype) self.assertEqual("added_fsuse", rule.fs) self.assertEqual("system:object_r:system:s0", rule.context) def test_removed_fs_uses(self): """Diff: removed fs_uses.""" l = sorted(self.diff.removed_fs_uses) self.assertEqual(1, len(l)) rule = l[0] self.assertEqual(FSURT.fs_use_task, rule.ruletype) self.assertEqual("removed_fsuse", rule.fs) self.assertEqual("system:object_r:system:s0", rule.context) def test_modified_fs_uses(self): """Diff: modified fs_uses.""" l = sorted(self.diff.modified_fs_uses, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_context, removed_context = l[0] self.assertEqual(FSURT.fs_use_trans, rule.ruletype) self.assertEqual("modified_fsuse", rule.fs) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # genfscon # def test_added_genfscons(self): """Diff: added genfscons.""" l = sorted(self.diff.added_genfscons) self.assertEqual(2, len(l)) rule = l[0] self.assertEqual("added_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("added_user:object_r:system:s0", rule.context) rule = l[1] self.assertEqual("change_path", rule.fs) self.assertEqual("/new", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) def test_removed_genfscons(self): """Diff: removed genfscons.""" l = sorted(self.diff.removed_genfscons) self.assertEqual(2, len(l)) rule = l[0] self.assertEqual("change_path", rule.fs) self.assertEqual("/old", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) rule = l[1] self.assertEqual("removed_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) def test_modified_genfscons(self): """Diff: modified genfscons.""" l = sorted(self.diff.modified_genfscons, key=lambda x: x.rule) self.assertEqual(1, len(l)) rule, added_context, removed_context = l[0] self.assertEqual("modified_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # level decl # def test_added_levels(self): """Diff: added levels.""" l = sorted(self.diff.added_levels) self.assertEqual(1, len(l)) self.assertEqual("s46:c0.c4", l[0]) def test_removed_levels(self): """Diff: removed levels.""" l = sorted(self.diff.removed_levels) self.assertEqual(1, len(l)) self.assertEqual("s47:c0.c4", l[0]) def test_modified_levels(self): """Diff: modified levels.""" l = sorted(self.diff.modified_levels) self.assertEqual(2, len(l)) level = l[0] self.assertEqual("s40", level.level.sensitivity) self.assertSetEqual(set(["c3"]), level.added_categories) self.assertFalse(level.removed_categories) level = l[1] self.assertEqual("s41", level.level.sensitivity) self.assertFalse(level.added_categories) self.assertSetEqual(set(["c4"]), level.removed_categories) # # netifcon # def test_added_netifcons(self): """Diff: added netifcons.""" l = sorted(self.diff.added_netifcons) self.assertEqual(1, len(l)) rule = l[0] self.assertEqual("added_netif", rule.netif) self.assertEqual("system:object_r:system:s0", rule.context) self.assertEqual("system:object_r:system:s0", rule.packet) def test_removed_netifcons(self): """Diff: removed netifcons.""" l = sorted(self.diff.removed_netifcons) self.assertEqual(1, len(l)) rule = l[0] self.assertEqual("removed_netif", rule.netif) self.assertEqual("system:object_r:system:s0", rule.context) self.assertEqual("system:object_r:system:s0", rule.packet) def test_modified_netifcons(self): """Diff: modified netifcons.""" l = sorted(self.diff.modified_netifcons, key=lambda x: x.rule) self.assertEqual(3, len(l)) # modified both contexts rule, added_context, removed_context, added_packet, removed_packet = l[0] self.assertEqual("mod_both_netif", rule.netif) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) self.assertEqual("added_user:object_r:system:s0", added_packet) self.assertEqual("removed_user:object_r:system:s0", removed_packet) # modified context rule, added_context, removed_context, added_packet, removed_packet = l[1] self.assertEqual("mod_ctx_netif", rule.netif) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) self.assertIsNone(added_packet) self.assertIsNone(removed_packet) # modified packet context rule, added_context, removed_context, added_packet, removed_packet = l[2] self.assertEqual("mod_pkt_netif", rule.netif) self.assertIsNone(added_context) self.assertIsNone(removed_context) self.assertEqual("added_user:object_r:system:s0", added_packet) self.assertEqual("removed_user:object_r:system:s0", removed_packet) # # nodecons # def test_added_nodecons(self): """Diff: added nodecons.""" l = sorted(self.diff.added_nodecons) self.assertEqual(4, len(l)) # new IPv4 nodecon = l[0] self.assertEqual("127.0.0.4", nodecon.address) self.assertEqual("255.255.255.255", nodecon.netmask) # changed IPv4 netmask nodecon = l[1] self.assertEqual("127.0.0.5", nodecon.address) self.assertEqual("255.255.255.0", nodecon.netmask) # new IPv6 nodecon = l[2] self.assertEqual("::4", nodecon.address) self.assertEqual("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", nodecon.netmask) # changed IPv6 netmask nodecon = l[3] self.assertEqual("::5", nodecon.address) self.assertEqual("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0", nodecon.netmask) def test_removed_nodecons(self): """Diff: removed nodecons.""" l = sorted(self.diff.removed_nodecons) self.assertEqual(4, len(l)) # new IPv4 nodecon = l[0] self.assertEqual("127.0.0.2", nodecon.address) self.assertEqual("255.255.255.255", nodecon.netmask) # changed IPv4 netmask nodecon = l[1] self.assertEqual("127.0.0.5", nodecon.address) self.assertEqual("255.255.255.255", nodecon.netmask) # new IPv6 nodecon = l[2] self.assertEqual("::2", nodecon.address) self.assertEqual("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", nodecon.netmask) # changed IPv6 netmask nodecon = l[3] self.assertEqual("::5", nodecon.address) self.assertEqual("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", nodecon.netmask) def test_modified_nodecons(self): """Diff: modified nodecons.""" l = sorted(self.diff.modified_nodecons, key=lambda x: x.rule) self.assertEqual(2, len(l)) # changed IPv4 nodecon, added_context, removed_context = l[0] self.assertEqual("127.0.0.3", nodecon.address) self.assertEqual("255.255.255.255", nodecon.netmask) self.assertEqual("modified_change_level:object_r:system:s2:c0", added_context) self.assertEqual("modified_change_level:object_r:system:s2:c1", removed_context) # changed IPv6 nodecon, added_context, removed_context = l[1] self.assertEqual("::3", nodecon.address) self.assertEqual("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", nodecon.netmask) self.assertEqual("modified_change_level:object_r:system:s2:c1", added_context) self.assertEqual("modified_change_level:object_r:system:s2:c0.c1", removed_context) # # Policy capabilities # def test_added_polcaps(self): """Diff: added polcaps.""" self.assertSetEqual(set(["always_check_network"]), self.diff.added_polcaps) def test_removed_polcaps(self): """Diff: removed polcaps.""" self.assertSetEqual(set(["network_peer_controls"]), self.diff.removed_polcaps) # # portcons # def test_added_portcons(self): """Diff: added portcons.""" l = sorted(self.diff.added_portcons) self.assertEqual(2, len(l)) portcon = l[0] self.assertEqual(IPPROTO_TCP, portcon.protocol) self.assertTupleEqual((2024, 2026), portcon.ports) portcon = l[1] self.assertEqual(IPPROTO_UDP, portcon.protocol) self.assertTupleEqual((2024, 2024), portcon.ports) def test_removed_portcons(self): """Diff: removed portcons.""" l = sorted(self.diff.removed_portcons) self.assertEqual(2, len(l)) portcon = l[0] self.assertEqual(IPPROTO_TCP, portcon.protocol) self.assertTupleEqual((1024, 1026), portcon.ports) portcon = l[1] self.assertEqual(IPPROTO_UDP, portcon.protocol) self.assertTupleEqual((1024, 1024), portcon.ports) def test_modified_portcons(self): """Diff: modified portcons.""" l = sorted(self.diff.modified_portcons, key=lambda x: x.rule) self.assertEqual(2, len(l)) portcon, added_context, removed_context = l[0] self.assertEqual(IPPROTO_TCP, portcon.protocol) self.assertTupleEqual((3024, 3026), portcon.ports) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) portcon, added_context, removed_context = l[1] self.assertEqual(IPPROTO_UDP, portcon.protocol) self.assertTupleEqual((3024, 3024), portcon.ports) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # defaults # def test_added_defaults(self): """Diff: added defaults.""" l = sorted(self.diff.added_defaults) self.assertEqual(2, len(l)) default = l[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow2", default.tclass) default = l[1] self.assertEqual(DRT.default_user, default.ruletype) self.assertEqual("infoflow2", default.tclass) def test_removed_defaults(self): """Diff: removed defaults.""" l = sorted(self.diff.removed_defaults) self.assertEqual(2, len(l)) default = l[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow3", default.tclass) default = l[1] self.assertEqual(DRT.default_role, default.ruletype) self.assertEqual("infoflow3", default.tclass) def test_modified_defaults(self): """Diff: modified defaults.""" l = sorted(self.diff.modified_defaults, key=lambda x: x.rule) self.assertEqual(4, len(l)) default, added_default, removed_default, added_range, removed_range = l[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow4", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertIsNone(added_range) self.assertIsNone(removed_range) default, added_default, removed_default, added_range, removed_range = l[1] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow5", default.tclass) self.assertIsNone(added_default) self.assertIsNone(removed_default) self.assertEqual(DRV.high, added_range) self.assertEqual(DRV.low, removed_range) default, added_default, removed_default, added_range, removed_range = l[2] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow6", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertEqual(DRV.low, added_range) self.assertEqual(DRV.high, removed_range) default, added_default, removed_default, added_range, removed_range = l[3] self.assertEqual(DRT.default_type, default.ruletype) self.assertEqual("infoflow4", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertIsNone(added_range) self.assertIsNone(removed_range) # # constrains # def test_added_constrains(self): """Diff: added constrains.""" l = sorted(self.diff.added_constrains) self.assertEqual(2, len(l)) constrain = l[0] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow3", constrain.tclass) self.assertSetEqual(set(["null"]), constrain.perms) self.assertListEqual(["u1", "u2", "!="], constrain.postfix_expression()) constrain = l[1] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow5", constrain.tclass) self.assertSetEqual(set(["hi_r"]), constrain.perms) self.assertListEqual( ['u1', 'u2', '==', 'r1', 'r2', '==', 'and', 't1', set(["system"]), '!=', 'or'], constrain.postfix_expression()) def test_removed_constrains(self): """Diff: removed constrains.""" l = sorted(self.diff.removed_constrains) self.assertEqual(2, len(l)) constrain = l[0] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow4", constrain.tclass) self.assertSetEqual(set(["hi_w"]), constrain.perms) self.assertListEqual(["u1", "u2", "!="], constrain.postfix_expression()) constrain = l[1] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow5", constrain.tclass) self.assertSetEqual(set(["hi_r"]), constrain.perms) self.assertListEqual( ['u1', 'u2', '==', 'r1', 'r2', '==', 'and', 't1', set(["system"]), '==', 'or'], constrain.postfix_expression()) # # mlsconstrains # def test_added_mlsconstrains(self): """Diff: added mlsconstrains.""" l = sorted(self.diff.added_mlsconstrains) self.assertEqual(2, len(l)) mlsconstrain = l[0] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow3", mlsconstrain.tclass) self.assertSetEqual(set(["null"]), mlsconstrain.perms) self.assertListEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'domby', 'and', 't1', set(["mls_exempt"]), '!=', 'or'], mlsconstrain.postfix_expression()) mlsconstrain = l[1] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow5", mlsconstrain.tclass) self.assertSetEqual(set(["hi_r"]), mlsconstrain.perms) self.assertListEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'incomp', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.postfix_expression()) def test_removed_mlsconstrains(self): """Diff: removed mlsconstrains.""" l = sorted(self.diff.removed_mlsconstrains) self.assertEqual(2, len(l)) mlsconstrain = l[0] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow4", mlsconstrain.tclass) self.assertSetEqual(set(["hi_w"]), mlsconstrain.perms) self.assertListEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'domby', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.postfix_expression()) mlsconstrain = l[1] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow5", mlsconstrain.tclass) self.assertSetEqual(set(["hi_r"]), mlsconstrain.perms) self.assertListEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'dom', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.postfix_expression()) # # validatetrans # def test_added_validatetrans(self): """Diff: added validatetrans.""" l = sorted(self.diff.added_validatetrans) self.assertEqual(2, len(l)) validatetrans = l[0] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow3", validatetrans.tclass) self.assertListEqual( ['t1', 't2', '==', 't3', set(["system"]), '==', 'or'], validatetrans.postfix_expression()) validatetrans = l[1] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow5", validatetrans.tclass) self.assertListEqual( ['u1', 'u2', '!=', 'r1', 'r2', '==', 'and', 't3', set(["system"]), '==', 'or'], validatetrans.postfix_expression()) def test_removed_validatetrans(self): """Diff: removed validatetrans.""" l = sorted(self.diff.removed_validatetrans) self.assertEqual(2, len(l)) validatetrans = l[0] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow4", validatetrans.tclass) self.assertListEqual( ['u1', 'u2', '==', 't3', set(["system"]), '==', 'or'], validatetrans.postfix_expression()) validatetrans = l[1] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow5", validatetrans.tclass) self.assertListEqual( ['u1', 'u2', '==', 'r1', 'r2', '!=', 'and', 't3', set(["system"]), '==', 'or'], validatetrans.postfix_expression()) # # mlsvalidatetrans # def test_added_mlsvalidatetrans(self): """Diff: added mlsvalidatetrans.""" l = sorted(self.diff.added_mlsvalidatetrans) self.assertEqual(2, len(l)) mlsvalidatetrans = l[0] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow3", mlsvalidatetrans.tclass) self.assertListEqual( ['l1', 'l2', '==', 'h1', 'h2', '==', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.postfix_expression()) mlsvalidatetrans = l[1] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow5", mlsvalidatetrans.tclass) self.assertListEqual( ['l1', 'l2', 'incomp', 'h1', 'h2', 'domby', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.postfix_expression()) def test_removed_mlsvalidatetrans(self): """Diff: removed mlsvalidatetrans.""" l = sorted(self.diff.removed_mlsvalidatetrans) self.assertEqual(2, len(l)) mlsvalidatetrans = l[0] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow4", mlsvalidatetrans.tclass) self.assertListEqual( ['l1', 'l2', '==', 'h1', 'h2', '==', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.postfix_expression()) mlsvalidatetrans = l[1] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow5", mlsvalidatetrans.tclass) self.assertListEqual( ['l1', 'l2', 'dom', 'h1', 'h2', 'dom', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.postfix_expression()) # # typebounds # def test_added_typebounds(self): """Diff: added typebounds.""" l = sorted(self.diff.added_typebounds) self.assertEqual(1, len(l)) bounds = l[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("added_parent", bounds.parent) self.assertEqual("added_child", bounds.child) def test_removed_typebounds(self): """Diff: removed typebounds.""" l = sorted(self.diff.removed_typebounds) self.assertEqual(1, len(l)) bounds = l[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("removed_parent", bounds.parent) self.assertEqual("removed_child", bounds.child) def test_modified_typebounds(self): """Diff: modified typebounds.""" l = sorted(self.diff.modified_typebounds, key=lambda x: x.rule) self.assertEqual(1, len(l)) bounds, added_bound, removed_bound = l[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("mod_child", bounds.child) self.assertEqual("mod_parent_added", added_bound) self.assertEqual("mod_parent_removed", removed_bound) # # Allowxperm rules # def test_added_allowxperm_rules(self): """Diff: added allowxperm rules.""" rules = sorted(self.diff.added_allowxperms) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.allowxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") # added rule with existing types self.validate_rule(rules[1], TRT.allowxperm, "ax_added_rule_source", "ax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_allowxperm_rules(self): """Diff: removed allowxperm rules.""" rules = sorted(self.diff.removed_allowxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.allowxperm, "ax_removed_rule_source", "ax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.allowxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_allowxperm_rules(self): """Diff: modified allowxperm rules.""" l = sorted(self.diff.modified_allowxperms, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_add_perms", rule.source) self.assertEqual("ax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_add_remove_perms", rule.source) self.assertEqual("ax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_remove_perms", rule.source) self.assertEqual("ax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Auditallowxperm rules # def test_added_auditallowxperm_rules(self): """Diff: added auditallowxperm rules.""" rules = sorted(self.diff.added_auditallowxperms) self.assertEqual(2, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.auditallowxperm, "aax_added_rule_source", "aax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # added rule with new type self.validate_rule(rules[1], TRT.auditallowxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_removed_auditallowxperm_rules(self): """Diff: removed auditallowxperm rules.""" rules = sorted(self.diff.removed_auditallowxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.auditallowxperm, "aax_removed_rule_source", "aax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.auditallowxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_auditallowxperm_rules(self): """Diff: modified auditallowxperm rules.""" l = sorted(self.diff.modified_auditallowxperms, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_add_perms", rule.source) self.assertEqual("aax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_add_remove_perms", rule.source) self.assertEqual("aax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_remove_perms", rule.source) self.assertEqual("aax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Neverallowxperm rules # def test_added_neverallowxperm_rules(self): """Diff: added neverallowxperm rules.""" rules = sorted(self.diff.added_neverallowxperms) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.neverallowxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") # added rule with existing types self.validate_rule(rules[1], TRT.neverallowxperm, "nax_added_rule_source", "nax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_neverallowxperm_rules(self): """Diff: removed neverallowxperm rules.""" rules = sorted(self.diff.removed_neverallowxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.neverallowxperm, "nax_removed_rule_source", "nax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.neverallowxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_neverallowxperm_rules(self): """Diff: modified neverallowxperm rules.""" l = sorted(self.diff.modified_neverallowxperms, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.neverallowxperm, rule.ruletype) self.assertEqual("nax_modified_rule_add_perms", rule.source) self.assertEqual("nax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.neverallowxperm, rule.ruletype) self.assertEqual("nax_modified_rule_add_remove_perms", rule.source) self.assertEqual("nax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.neverallowxperm, rule.ruletype) self.assertEqual("nax_modified_rule_remove_perms", rule.source) self.assertEqual("nax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Dontauditxperm rules # def test_added_dontauditxperm_rules(self): """Diff: added dontauditxperm rules.""" rules = sorted(self.diff.added_dontauditxperms) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.dontauditxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") # added rule with existing types self.validate_rule(rules[1], TRT.dontauditxperm, "dax_added_rule_source", "dax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_dontauditxperm_rules(self): """Diff: removed dontauditxperm rules.""" rules = sorted(self.diff.removed_dontauditxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.dontauditxperm, "dax_removed_rule_source", "dax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.dontauditxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_dontauditxperm_rules(self): """Diff: modified dontauditxperm rules.""" l = sorted(self.diff.modified_dontauditxperms, key=lambda x: x.rule) self.assertEqual(3, len(l)) # add permissions rule, added_perms, removed_perms, matched_perms = l[0] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_add_perms", rule.source) self.assertEqual("dax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = l[1] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_add_remove_perms", rule.source) self.assertEqual("dax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = l[2] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_remove_perms", rule.source) self.assertEqual("dax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) class PolicyDifferenceTestNoDiff(unittest.TestCase): """Policy difference test with no policy differences.""" @classmethod def setUpClass(cls): cls.diff = PolicyDifference(SELinuxPolicy("tests/diff_left.conf"), SELinuxPolicy("tests/diff_left.conf")) def test_added_types(self): """NoDiff: no added types""" self.assertFalse(self.diff.added_types) def test_removed_types(self): """NoDiff: no removed types""" self.assertFalse(self.diff.removed_types) def test_modified_types(self): """NoDiff: no modified types""" self.assertFalse(self.diff.modified_types) def test_added_roles(self): """NoDiff: no added roles.""" self.assertFalse(self.diff.added_roles) def test_removed_roles(self): """NoDiff: no removed roles.""" self.assertFalse(self.diff.removed_roles) def test_modified_roles(self): """NoDiff: no modified roles.""" self.assertFalse(self.diff.modified_roles) def test_added_commons(self): """NoDiff: no added commons.""" self.assertFalse(self.diff.added_commons) def test_removed_commons(self): """NoDiff: no removed commons.""" self.assertFalse(self.diff.removed_commons) def test_modified_commons(self): """NoDiff: no modified commons.""" self.assertFalse(self.diff.modified_commons) def test_added_classes(self): """NoDiff: no added classes.""" self.assertFalse(self.diff.added_classes) def test_removed_classes(self): """NoDiff: no removed classes.""" self.assertFalse(self.diff.removed_classes) def test_modified_classes(self): """NoDiff: no modified classes.""" self.assertFalse(self.diff.modified_classes) def test_added_allows(self): """NoDiff: no added allow rules.""" self.assertFalse(self.diff.added_allows) def test_removed_allows(self): """NoDiff: no removed allow rules.""" self.assertFalse(self.diff.removed_allows) def test_modified_allows(self): """NoDiff: no modified allow rules.""" self.assertFalse(self.diff.modified_allows) def test_added_auditallows(self): """NoDiff: no added auditallow rules.""" self.assertFalse(self.diff.added_auditallows) def test_removed_auditallows(self): """NoDiff: no removed auditallow rules.""" self.assertFalse(self.diff.removed_auditallows) def test_modified_auditallows(self): """NoDiff: no modified auditallow rules.""" self.assertFalse(self.diff.modified_auditallows) def test_added_neverallows(self): """NoDiff: no added neverallow rules.""" self.assertFalse(self.diff.added_neverallows) def test_removed_neverallows(self): """NoDiff: no removed neverallow rules.""" self.assertFalse(self.diff.removed_neverallows) def test_modified_neverallows(self): """NoDiff: no modified neverallow rules.""" self.assertFalse(self.diff.modified_neverallows) def test_added_dontaudits(self): """NoDiff: no added dontaudit rules.""" self.assertFalse(self.diff.added_dontaudits) def test_removed_dontaudits(self): """NoDiff: no removed dontaudit rules.""" self.assertFalse(self.diff.removed_dontaudits) def test_modified_dontaudits(self): """NoDiff: no modified dontaudit rules.""" self.assertFalse(self.diff.modified_dontaudits) def test_added_type_transitions(self): """NoDiff: no added type_transition rules.""" self.assertFalse(self.diff.added_type_transitions) def test_removed_type_transitions(self): """NoDiff: no removed type_transition rules.""" self.assertFalse(self.diff.removed_type_transitions) def test_modified_type_transitions(self): """NoDiff: no modified type_transition rules.""" self.assertFalse(self.diff.modified_type_transitions) def test_added_type_changes(self): """NoDiff: no added type_change rules.""" self.assertFalse(self.diff.added_type_changes) def test_removed_type_changes(self): """NoDiff: no removed type_change rules.""" self.assertFalse(self.diff.removed_type_changes) def test_modified_type_changes(self): """NoDiff: no modified type_change rules.""" self.assertFalse(self.diff.modified_type_changes) def test_added_type_members(self): """NoDiff: no added type_member rules.""" self.assertFalse(self.diff.added_type_members) def test_removed_type_members(self): """NoDiff: no removed type_member rules.""" self.assertFalse(self.diff.removed_type_members) def test_modified_type_members(self): """NoDiff: no modified type_member rules.""" self.assertFalse(self.diff.modified_type_members) def test_added_range_transitions(self): """NoDiff: no added range_transition rules.""" self.assertFalse(self.diff.added_range_transitions) def test_removed_range_transitions(self): """NoDiff: no removed range_transition rules.""" self.assertFalse(self.diff.removed_range_transitions) def test_modified_range_transitions(self): """NoDiff: no modified range_transition rules.""" self.assertFalse(self.diff.modified_range_transitions) def test_added_role_allows(self): """NoDiff: no added role_allow rules.""" self.assertFalse(self.diff.added_role_allows) def test_removed_role_allows(self): """NoDiff: no removed role_allow rules.""" self.assertFalse(self.diff.removed_role_allows) def test_modified_role_allows(self): """NoDiff: no modified role_allow rules.""" self.assertFalse(self.diff.modified_role_allows) def test_added_role_transitions(self): """NoDiff: no added role_transition rules.""" self.assertFalse(self.diff.added_role_transitions) def test_removed_role_transitions(self): """NoDiff: no removed role_transition rules.""" self.assertFalse(self.diff.removed_role_transitions) def test_modified_role_transitions(self): """NoDiff: no modified role_transition rules.""" self.assertFalse(self.diff.modified_role_transitions) def test_added_users(self): """NoDiff: no added users.""" self.assertFalse(self.diff.added_users) def test_removed_users(self): """NoDiff: no removed users.""" self.assertFalse(self.diff.removed_users) def test_modified_users(self): """NoDiff: no modified user rules.""" self.assertFalse(self.diff.modified_users) def test_added_type_attributes(self): """NoDiff: no added type attribute.""" self.assertFalse(self.diff.added_type_attributes) def test_removed_type_attributes(self): """NoDiff: no removed type attributes.""" self.assertFalse(self.diff.removed_type_attributes) def test_modified_type_attributes(self): """NoDiff: no modified type attributes.""" self.assertFalse(self.diff.modified_type_attributes) def test_added_booleans(self): """NoDiff: no added booleans.""" self.assertFalse(self.diff.added_booleans) def test_removed_booleans(self): """NoDiff: no removed booleans.""" self.assertFalse(self.diff.removed_booleans) def test_modified_booleans(self): """NoDiff: no modified booleans.""" self.assertFalse(self.diff.modified_booleans) def test_added_categories(self): """NoDiff: no added categories.""" self.assertFalse(self.diff.added_categories) def test_removed_categories(self): """NoDiff: no removed categories.""" self.assertFalse(self.diff.removed_categories) def test_modified_categories(self): """NoDiff: no modified categories.""" self.assertFalse(self.diff.modified_categories) def test_added_sensitivities(self): """NoDiff: no added sensitivities.""" self.assertFalse(self.diff.added_sensitivities) def test_removed_sensitivities(self): """NoDiff: no removed sensitivities.""" self.assertFalse(self.diff.removed_sensitivities) def test_modified_sensitivities(self): """NoDiff: no modified sensitivities.""" self.assertFalse(self.diff.modified_sensitivities) def test_added_initialsids(self): """NoDiff: no added initialsids.""" self.assertFalse(self.diff.added_initialsids) def test_removed_initialsids(self): """NoDiff: no removed initialsids.""" self.assertFalse(self.diff.removed_initialsids) def test_modified_initialsids(self): """NoDiff: no modified initialsids.""" self.assertFalse(self.diff.modified_initialsids) def test_added_fs_uses(self): """NoDiff: no added fs_uses.""" self.assertFalse(self.diff.added_fs_uses) def test_removed_fs_uses(self): """NoDiff: no removed fs_uses.""" self.assertFalse(self.diff.removed_fs_uses) def test_modified_fs_uses(self): """NoDiff: no modified fs_uses.""" self.assertFalse(self.diff.modified_fs_uses) def test_added_genfscons(self): """NoDiff: no added genfscons.""" self.assertFalse(self.diff.added_genfscons) def test_removed_genfscons(self): """NoDiff: no removed genfscons.""" self.assertFalse(self.diff.removed_genfscons) def test_modified_genfscons(self): """NoDiff: no modified genfscons.""" self.assertFalse(self.diff.modified_genfscons) def test_added_levels(self): """NoDiff: no added levels.""" self.assertFalse(self.diff.added_levels) def test_removed_levels(self): """NoDiff: no removed levels.""" self.assertFalse(self.diff.removed_levels) def test_modified_levels(self): """NoDiff: no modified levels.""" self.assertFalse(self.diff.modified_levels) def test_added_netifcons(self): """NoDiff: no added netifcons.""" self.assertFalse(self.diff.added_netifcons) def test_removed_netifcons(self): """NoDiff: no removed netifcons.""" self.assertFalse(self.diff.removed_netifcons) def test_modified_netifcons(self): """NoDiff: no modified netifcons.""" self.assertFalse(self.diff.modified_netifcons) def test_added_nodecons(self): """NoDiff: no added nodecons.""" self.assertFalse(self.diff.added_nodecons) def test_removed_nodecons(self): """NoDiff: no removed nodecons.""" self.assertFalse(self.diff.removed_nodecons) def test_modified_nodecons(self): """NoDiff: no modified nodecons.""" self.assertFalse(self.diff.modified_nodecons) def test_added_polcaps(self): """NoDiff: no added polcaps.""" self.assertFalse(self.diff.added_polcaps) def test_removed_polcaps(self): """NoDiff: no removed polcaps.""" self.assertFalse(self.diff.removed_polcaps) def test_added_portcons(self): """NoDiff: no added portcons.""" self.assertFalse(self.diff.added_portcons) def test_removed_portcons(self): """NoDiff: no removed portcons.""" self.assertFalse(self.diff.removed_portcons) def test_modified_portcons(self): """NoDiff: no modified portcons.""" self.assertFalse(self.diff.modified_portcons) def test_modified_properties(self): """NoDiff: no modified properties.""" self.assertFalse(self.diff.modified_properties) def test_added_defaults(self): """NoDiff: no added defaults.""" self.assertFalse(self.diff.added_defaults) def test_removed_defaults(self): """NoDiff: no removed defaults.""" self.assertFalse(self.diff.removed_defaults) def test_modified_defaults(self): """NoDiff: no modified defaults.""" self.assertFalse(self.diff.modified_defaults) def test_added_constrains(self): """NoDiff: no added constrains.""" self.assertFalse(self.diff.added_constrains) def test_removed_constrains(self): """NoDiff: no removed constrains.""" self.assertFalse(self.diff.removed_constrains) def test_added_mlsconstrains(self): """NoDiff: no added mlsconstrains.""" self.assertFalse(self.diff.added_mlsconstrains) def test_removed_mlsconstrains(self): """NoDiff: no removed mlsconstrains.""" self.assertFalse(self.diff.removed_mlsconstrains) def test_added_validatetrans(self): """NoDiff: no added validatetrans.""" self.assertFalse(self.diff.added_validatetrans) def test_removed_validatetrans(self): """NoDiff: no removed validatetrans.""" self.assertFalse(self.diff.removed_validatetrans) def test_added_mlsvalidatetrans(self): """NoDiff: no added mlsvalidatetrans.""" self.assertFalse(self.diff.added_mlsvalidatetrans) def test_removed_mlsvalidatetrans(self): """NoDiff: no removed mlsvalidatetrans.""" self.assertFalse(self.diff.removed_mlsvalidatetrans) def test_added_typebounds(self): """NoDiff: no added typebounds.""" self.assertFalse(self.diff.added_typebounds) def test_removed_typebounds(self): """NoDiff: no removed typebounds.""" self.assertFalse(self.diff.removed_typebounds) def test_modified_typebounds(self): """NoDiff: no modified typebounds.""" self.assertFalse(self.diff.modified_typebounds) def test_added_allowxperms(self): """NoDiff: no added allowxperm rules.""" self.assertFalse(self.diff.added_allowxperms) def test_removed_allowxperms(self): """NoDiff: no removed allowxperm rules.""" self.assertFalse(self.diff.removed_allowxperms) def test_modified_allowxperms(self): """NoDiff: no modified allowxperm rules.""" self.assertFalse(self.diff.modified_allowxperms) def test_added_auditallowxperms(self): """NoDiff: no added auditallowxperm rules.""" self.assertFalse(self.diff.added_auditallowxperms) def test_removed_auditallowxperms(self): """NoDiff: no removed auditallowxperm rules.""" self.assertFalse(self.diff.removed_auditallowxperms) def test_modified_auditallowxperms(self): """NoDiff: no modified auditallowxperm rules.""" self.assertFalse(self.diff.modified_auditallowxperms) def test_added_neverallowxperms(self): """NoDiff: no added neverallowxperm rules.""" self.assertFalse(self.diff.added_neverallowxperms) def test_removed_neverallowxperms(self): """NoDiff: no removed neverallowxperm rules.""" self.assertFalse(self.diff.removed_neverallowxperms) def test_modified_neverallowxperms(self): """NoDiff: no modified neverallowxperm rules.""" self.assertFalse(self.diff.modified_neverallowxperms) def test_added_dontauditxperms(self): """NoDiff: no added dontauditxperm rules.""" self.assertFalse(self.diff.added_dontauditxperms) def test_removed_dontauditxperms(self): """NoDiff: no removed dontauditxperm rules.""" self.assertFalse(self.diff.removed_dontauditxperms) def test_modified_dontauditxperms(self): """NoDiff: no modified dontauditxperm rules.""" self.assertFalse(self.diff.modified_dontauditxperms) class PolicyDifferenceTestMLStoStandard(unittest.TestCase): """ Policy difference test between MLS and standard (non-MLS) policy. The left policy is an MLS policy. The right policy is identical to the left policy, except with MLS disabled. """ @classmethod def setUpClass(cls): cls.diff = PolicyDifference(SELinuxPolicy("tests/diff_left.conf"), SELinuxPolicy("tests/diff_left_standard.conf")) def test_added_types(self): """MLSvsStandardDiff: no added types""" self.assertFalse(self.diff.added_types) def test_removed_types(self): """MLSvsStandardDiff: no removed types""" self.assertFalse(self.diff.removed_types) def test_modified_types(self): """MLSvsStandardDiff: no modified types""" self.assertFalse(self.diff.modified_types) def test_added_roles(self): """MLSvsStandardDiff: no added roles.""" self.assertFalse(self.diff.added_roles) def test_removed_roles(self): """MLSvsStandardDiff: no removed roles.""" self.assertFalse(self.diff.removed_roles) def test_modified_roles(self): """MLSvsStandardDiff: no modified roles.""" self.assertFalse(self.diff.modified_roles) def test_added_commons(self): """MLSvsStandardDiff: no added commons.""" self.assertFalse(self.diff.added_commons) def test_removed_commons(self): """MLSvsStandardDiff: no removed commons.""" self.assertFalse(self.diff.removed_commons) def test_modified_commons(self): """MLSvsStandardDiff: no modified commons.""" self.assertFalse(self.diff.modified_commons) def test_added_classes(self): """MLSvsStandardDiff: no added classes.""" self.assertFalse(self.diff.added_classes) def test_removed_classes(self): """MLSvsStandardDiff: no removed classes.""" self.assertFalse(self.diff.removed_classes) def test_modified_classes(self): """MLSvsStandardDiff: no modified classes.""" self.assertFalse(self.diff.modified_classes) def test_added_allows(self): """MLSvsStandardDiff: no added allow rules.""" self.assertFalse(self.diff.added_allows) def test_removed_allows(self): """MLSvsStandardDiff: no removed allow rules.""" self.assertFalse(self.diff.removed_allows) def test_modified_allows(self): """MLSvsStandardDiff: no modified allow rules.""" self.assertFalse(self.diff.modified_allows) def test_added_auditallows(self): """MLSvsStandardDiff: no added auditallow rules.""" self.assertFalse(self.diff.added_auditallows) def test_removed_auditallows(self): """MLSvsStandardDiff: no removed auditallow rules.""" self.assertFalse(self.diff.removed_auditallows) def test_modified_auditallows(self): """MLSvsStandardDiff: no modified auditallow rules.""" self.assertFalse(self.diff.modified_auditallows) def test_added_neverallows(self): """MLSvsStandardDiff: no added neverallow rules.""" self.assertFalse(self.diff.added_neverallows) def test_removed_neverallows(self): """MLSvsStandardDiff: no removed neverallow rules.""" self.assertFalse(self.diff.removed_neverallows) def test_modified_neverallows(self): """MLSvsStandardDiff: no modified neverallow rules.""" self.assertFalse(self.diff.modified_neverallows) def test_added_dontaudits(self): """MLSvsStandardDiff: no added dontaudit rules.""" self.assertFalse(self.diff.added_dontaudits) def test_removed_dontaudits(self): """MLSvsStandardDiff: no removed dontaudit rules.""" self.assertFalse(self.diff.removed_dontaudits) def test_modified_dontaudits(self): """MLSvsStandardDiff: no modified dontaudit rules.""" self.assertFalse(self.diff.modified_dontaudits) def test_added_type_transitions(self): """MLSvsStandardDiff: no added type_transition rules.""" self.assertFalse(self.diff.added_type_transitions) def test_removed_type_transitions(self): """MLSvsStandardDiff: no removed type_transition rules.""" self.assertFalse(self.diff.removed_type_transitions) def test_modified_type_transitions(self): """MLSvsStandardDiff: no modified type_transition rules.""" self.assertFalse(self.diff.modified_type_transitions) def test_added_type_changes(self): """MLSvsStandardDiff: no added type_change rules.""" self.assertFalse(self.diff.added_type_changes) def test_removed_type_changes(self): """MLSvsStandardDiff: no removed type_change rules.""" self.assertFalse(self.diff.removed_type_changes) def test_modified_type_changes(self): """MLSvsStandardDiff: no modified type_change rules.""" self.assertFalse(self.diff.modified_type_changes) def test_added_type_members(self): """MLSvsStandardDiff: no added type_member rules.""" self.assertFalse(self.diff.added_type_members) def test_removed_type_members(self): """MLSvsStandardDiff: no removed type_member rules.""" self.assertFalse(self.diff.removed_type_members) def test_modified_type_members(self): """MLSvsStandardDiff: no modified type_member rules.""" self.assertFalse(self.diff.modified_type_members) def test_added_range_transitions(self): """MLSvsStandardDiff: no added range_transition rules.""" self.assertFalse(self.diff.added_range_transitions) def test_removed_range_transitions(self): """MLSvsStandardDiff: all range_transition rules removed.""" self.assertEqual(self.diff.left_policy.range_transition_count, len(self.diff.removed_range_transitions)) def test_modified_range_transitions(self): """MLSvsStandardDiff: no modified range_transition rules.""" self.assertFalse(self.diff.modified_range_transitions) def test_added_role_allows(self): """MLSvsStandardDiff: no added role_allow rules.""" self.assertFalse(self.diff.added_role_allows) def test_removed_role_allows(self): """MLSvsStandardDiff: no removed role_allow rules.""" self.assertFalse(self.diff.removed_role_allows) def test_modified_role_allows(self): """MLSvsStandardDiff: no modified role_allow rules.""" self.assertFalse(self.diff.modified_role_allows) def test_added_role_transitions(self): """MLSvsStandardDiff: no added role_transition rules.""" self.assertFalse(self.diff.added_role_transitions) def test_removed_role_transitions(self): """MLSvsStandardDiff: no removed role_transition rules.""" self.assertFalse(self.diff.removed_role_transitions) def test_modified_role_transitions(self): """MLSvsStandardDiff: no modified role_transition rules.""" self.assertFalse(self.diff.modified_role_transitions) def test_added_users(self): """MLSvsStandardDiff: no added users.""" self.assertFalse(self.diff.added_users) def test_removed_users(self): """MLSvsStandardDiff: no removed users.""" self.assertFalse(self.diff.removed_users) def test_modified_users(self): """MLSvsStandardDiff: all users modified.""" self.assertEqual(self.diff.left_policy.user_count, len(self.diff.modified_users)) def test_added_type_attributes(self): """MLSvsStandardDiff: no added type attribute.""" self.assertFalse(self.diff.added_type_attributes) def test_removed_type_attributes(self): """MLSvsStandardDiff: no removed type attributes.""" self.assertFalse(self.diff.removed_type_attributes) def test_modified_type_attributes(self): """MLSvsStandardDiff: no modified type attributes.""" self.assertFalse(self.diff.modified_type_attributes) def test_added_booleans(self): """MLSvsStandardDiff: no added booleans.""" self.assertFalse(self.diff.added_booleans) def test_removed_booleans(self): """MLSvsStandardDiff: no removed booleans.""" self.assertFalse(self.diff.removed_booleans) def test_modified_booleans(self): """MLSvsStandardDiff: no modified booleans.""" self.assertFalse(self.diff.modified_booleans) def test_added_categories(self): """MLSvsStandardDiff: no added categories.""" self.assertFalse(self.diff.added_categories) def test_removed_categories(self): """MLSvsStandardDiff: all categories removed.""" self.assertEqual(self.diff.left_policy.category_count, len(self.diff.removed_categories)) def test_modified_categories(self): """MLSvsStandardDiff: no modified categories.""" self.assertFalse(self.diff.modified_categories) def test_added_sensitivities(self): """MLSvsStandardDiff: no added sensitivities.""" self.assertFalse(self.diff.added_sensitivities) def test_removed_sensitivities(self): """MLSvsStandardDiff: all sensitivities removed.""" self.assertEqual(self.diff.left_policy.level_count, len(self.diff.removed_sensitivities)) def test_modified_sensitivities(self): """MLSvsStandardDiff: no modified sensitivities.""" self.assertFalse(self.diff.modified_sensitivities) def test_added_initialsids(self): """MLSvsStandardDiff: no added initialsids.""" self.assertFalse(self.diff.added_initialsids) def test_removed_initialsids(self): """MLSvsStandardDiff: no removed initialsids.""" self.assertFalse(self.diff.removed_initialsids) def test_modified_initialsids(self): """MLSvsStandardDiff: all initialsids modified.""" self.assertEqual(self.diff.left_policy.initialsids_count, len(self.diff.modified_initialsids)) def test_added_fs_uses(self): """MLSvsStandardDiff: no added fs_uses.""" self.assertFalse(self.diff.added_fs_uses) def test_removed_fs_uses(self): """MLSvsStandardDiff: no removed fs_uses.""" self.assertFalse(self.diff.removed_fs_uses) def test_modified_fs_uses(self): """MLSvsStandardDiff: all fs_uses modified.""" self.assertEqual(self.diff.left_policy.fs_use_count, len(self.diff.modified_fs_uses)) def test_added_genfscons(self): """MLSvsStandardDiff: no added genfscons.""" self.assertFalse(self.diff.added_genfscons) def test_removed_genfscons(self): """MLSvsStandardDiff: no removed genfscons.""" self.assertFalse(self.diff.removed_genfscons) def test_modified_genfscons(self): """MLSvsStandardDiff: all genfscons modified.""" self.assertEqual(self.diff.left_policy.genfscon_count, len(self.diff.modified_genfscons)) def test_added_levels(self): """MLSvsStandardDiff: no added levels.""" self.assertFalse(self.diff.added_levels) def test_removed_levels(self): """MLSvsStandardDiff: all levels removed.""" self.assertEqual(self.diff.left_policy.level_count, len(self.diff.removed_levels)) def test_modified_levels(self): """MLSvsStandardDiff: no modified levels.""" self.assertFalse(self.diff.modified_levels) def test_added_netifcons(self): """MLSvsStandardDiff: no added netifcons.""" self.assertFalse(self.diff.added_netifcons) def test_removed_netifcons(self): """MLSvsStandardDiff: no removed netifcons.""" self.assertFalse(self.diff.removed_netifcons) def test_modified_netifcons(self): """MLSvsStandardDiff: all netifcons modified.""" self.assertEqual(self.diff.left_policy.netifcon_count, len(self.diff.modified_netifcons)) def test_added_nodecons(self): """MLSvsStandardDiff: no added nodecons.""" self.assertFalse(self.diff.added_nodecons) def test_removed_nodecons(self): """MLSvsStandardDiff: no removed nodecons.""" self.assertFalse(self.diff.removed_nodecons) def test_modified_nodecons(self): """MLSvsStandardDiff: all nodecons modified.""" self.assertEqual(self.diff.left_policy.nodecon_count, len(self.diff.modified_nodecons)) def test_added_polcaps(self): """MLSvsStandardDiff: no added polcaps.""" self.assertFalse(self.diff.added_polcaps) def test_removed_polcaps(self): """MLSvsStandardDiff: no removed polcaps.""" self.assertFalse(self.diff.removed_polcaps) def test_added_portcons(self): """MLSvsStandardDiff: no added portcons.""" self.assertFalse(self.diff.added_portcons) def test_removed_portcons(self): """MLSvsStandardDiff: no removed portcons.""" self.assertFalse(self.diff.removed_portcons) def test_modified_portcons(self): """MLSvsStandardDiff: all portcons modified.""" self.assertEqual(self.diff.left_policy.portcon_count, len(self.diff.modified_portcons)) def test_modified_properties(self): """MLSvsStandardDiff: MLS property modified only.""" self.assertEqual(1, len(self.diff.modified_properties)) name, added, removed = self.diff.modified_properties[0] self.assertEqual("MLS", name) self.assertIs(False, added) self.assertIs(True, removed) def test_added_defaults(self): """MLSvsStandardDiff: no added defaults.""" self.assertFalse(self.diff.added_defaults) def test_removed_defaults(self): """MLSvsStandardDiff: all default_range removed.""" self.assertEqual( sum(1 for d in self.diff.left_policy.defaults() if d.ruletype == DRT.default_range), len(self.diff.removed_defaults)) def test_modified_defaults(self): """MLSvsStandardDiff: no defaults modified.""" self.assertFalse(self.diff.modified_defaults) def test_added_constraints(self): """MLSvsStandardDiff: no added constraints.""" self.assertFalse(self.diff.added_constrains) def test_removed_constraints(self): """MLSvsStandardDiff: no removed constraints.""" self.assertFalse(self.diff.removed_constrains) def test_added_validatetrans(self): """MLSvsStandardDiff: no added validatetrans.""" self.assertFalse(self.diff.added_validatetrans) def test_removed_validatetrans(self): """MLSvsStandardDiff: no removed validatetrans.""" self.assertFalse(self.diff.removed_validatetrans) def test_added_mlsconstraints(self): """MLSvsStandardDiff: no added mlsconstraints.""" self.assertFalse(self.diff.added_mlsconstrains) def test_removed_mlsconstraints(self): """MLSvsStandardDiff: all mlsconstraints removed.""" self.assertEqual( sum(1 for m in self.diff.left_policy.constraints() if m.ruletype == CRT.mlsconstrain), len(self.diff.removed_mlsconstrains)) def test_added_mlsvalidatetrans(self): """MLSvsStandardDiff: no added mlsvalidatetrans.""" self.assertFalse(self.diff.added_mlsvalidatetrans) def test_removed_mlsvalidatetrans(self): """MLSvsStandardDiff: all mlsvalidatetrans removed.""" self.assertEqual( sum(1 for m in self.diff.left_policy.constraints() if m.ruletype == CRT.mlsvalidatetrans), len(self.diff.removed_mlsvalidatetrans)) def test_added_typebounds(self): """MLSvsStandardDiff: no added typebounds.""" self.assertFalse(self.diff.added_typebounds) def test_removed_typebounds(self): """MLSvsStandardDiff: no removed typebounds.""" self.assertFalse(self.diff.removed_typebounds) def test_modified_typebounds(self): """MLSvsStandardDiff: no modified typebounds.""" self.assertFalse(self.diff.modified_typebounds) def test_added_allowxperms(self): """NoDiff: no added allowxperm rules.""" self.assertFalse(self.diff.added_allowxperms) def test_removed_allowxperms(self): """NoDiff: no removed allowxperm rules.""" self.assertFalse(self.diff.removed_allowxperms) def test_modified_allowxperms(self): """NoDiff: no modified allowxperm rules.""" self.assertFalse(self.diff.modified_allowxperms) def test_added_auditallowxperms(self): """NoDiff: no added auditallowxperm rules.""" self.assertFalse(self.diff.added_auditallowxperms) def test_removed_auditallowxperms(self): """NoDiff: no removed auditallowxperm rules.""" self.assertFalse(self.diff.removed_auditallowxperms) def test_modified_auditallowxperms(self): """NoDiff: no modified auditallowxperm rules.""" self.assertFalse(self.diff.modified_auditallowxperms) def test_added_neverallowxperms(self): """NoDiff: no added neverallowxperm rules.""" self.assertFalse(self.diff.added_neverallowxperms) def test_removed_neverallowxperms(self): """NoDiff: no removed neverallowxperm rules.""" self.assertFalse(self.diff.removed_neverallowxperms) def test_modified_neverallowxperms(self): """NoDiff: no modified neverallowxperm rules.""" self.assertFalse(self.diff.modified_neverallowxperms) def test_added_dontauditxperms(self): """NoDiff: no added dontauditxperm rules.""" self.assertFalse(self.diff.added_dontauditxperms) def test_removed_dontauditxperms(self): """NoDiff: no removed dontauditxperm rules.""" self.assertFalse(self.diff.removed_dontauditxperms) def test_modified_dontauditxperms(self): """NoDiff: no modified dontauditxperm rules.""" self.assertFalse(self.diff.modified_dontauditxperms) setools-4.1.1/tests/diff_left.conf000066400000000000000000000614311314142262400171440ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid matched_sid sid removed_sid sid modified_sid common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: # removed: default_role infoflow3 source; default_range infoflow3 target high; # modified: default_type infoflow4 source; default_range infoflow4 source low; # modified range: default_range infoflow5 target low; # modified both default_range infoflow6 source high; sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint # removed mls constraint mlsconstrain infoflow4 hi_w ((l1 domby l2 and h1 domby h2) or (t1 == mls_exempt)); # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 dom h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans # removed mls validatetrans mlsvalidatetrans infoflow4 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 dom l2 and h1 dom h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; range_transition rt_removed_rule_source rt_removed_rule_target:infoflow s1; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_matched_source system:infoflow s2:c0 - s3:c0.c2; range_transition removed_type system:infoflow4 s1; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #range_transition rt_move_to_bool system:infoflow3 s0; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #range_transition rt_move_from_bool system:infoflow4 s0; #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #range_transition system rt_switch_block:infoflow6 s0; #} else { #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_A_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c3; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid matched_sid system:system:system:s0 sid removed_sid removed_user:system:system:s0 sid modified_sid system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 # removed nodecons nodecon 127.0.0.2 255.255.255.255 removed_user:object_r:system:s0 nodecon ::2 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff removed_user:object_r:system:s0 # modified nodecons nodecon 127.0.0.3 255.255.255.255 modified_change_level:object_r:system:s2:c1 nodecon ::3 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 127.0.0.5 255.255.255.255 system:object_r:system:s0 nodecon ::5 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/diff_left_standard.conf000066400000000000000000000544651314142262400210350ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid matched_sid sid removed_sid sid modified_sid common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; # added: # removed: default_role infoflow3 source; # modified: default_type infoflow4 source; attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; type rt_matched_source; type rt_matched_target; type rt_removed_rule_source; type rt_removed_rule_target; type rt_added_rule_source; type rt_added_rule_target; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #} else { #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system; user removed_user roles system; user modified_add_role roles system; user modified_remove_role roles { system removed_role }; user modified_change_level roles system; user modified_change_range roles system; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system sid security system:system:system sid matched_sid system:system:system sid removed_sid removed_user:system:system sid modified_sid system:system:system #fs_use fs_use_trans devpts system:object_r:system; fs_use_xattr ext3 system:object_r:system; fs_use_task pipefs system:object_r:system; fs_use_task removed_fsuse system:object_r:system; fs_use_trans modified_fsuse removed_user:object_r:system; #genfscon genfscon proc / system:object_r:system genfscon proc /sys system:object_r:system genfscon selinuxfs / system:object_r:system genfscon removed_genfs / system:object_r:system genfscon change_path /old system:object_r:system genfscon modified_genfs / -s removed_user:object_r:system # matched portcons portcon tcp 80 system:object_r:system portcon udp 80 system:object_r:system portcon udp 30-40 system:object_r:system # removed portcons portcon udp 1024 system:object_r:system portcon tcp 1024-1026 system:object_r:system # modified portcons portcon udp 3024 removed_user:object_r:system portcon tcp 3024-3026 removed_user:object_r:system netifcon eth0 system:object_r:system system:object_r:system netifcon removed_netif system:object_r:system system:object_r:system netifcon mod_ctx_netif removed_user:object_r:system system:object_r:system netifcon mod_pkt_netif system:object_r:system removed_user:object_r:system netifcon mod_both_netif removed_user:object_r:system removed_user:object_r:system # matched nodecons nodecon 127.0.0.1 255.255.255.255 system:object_r:system nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system # removed nodecons nodecon 127.0.0.2 255.255.255.255 removed_user:object_r:system nodecon ::2 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff removed_user:object_r:system # modified nodecons nodecon 127.0.0.3 255.255.255.255 modified_change_level:object_r:system nodecon ::3 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff modified_change_level:object_r:system # change netmask (add/remove) nodecon 127.0.0.5 255.255.255.255 system:object_r:system nodecon ::5 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system setools-4.1.1/tests/diff_right.conf000066400000000000000000000641251314142262400173320ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class added_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid matched_sid sid added_sid sid modified_sid common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common added_common { new_com } common modified_remove_perm { same_perm } common modified_add_perm { matched_perm added_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class added_class { new_class_perm } class modified_add_perm { same_perm added_perm } class modified_remove_perm { same_perm } class modified_change_common inherits added_common # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: default_user infoflow2 target; default_range infoflow2 source low; # removed: # modified: default_type infoflow4 target; default_range infoflow4 target low; # modified range: default_range infoflow5 target high; # modified both default_range infoflow6 target low; sensitivity s0 alias { al1 }; sensitivity s1 alias { al3 al4 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s46; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 } category c0 alias { spam }; category c1 alias { foo bar }; category c2; category c3; category c4; category c6; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1,c3; level s41:c0.c3; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s46:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint mlsconstrain infoflow3 null ((l1 domby l2 and h1 domby h2) or (t1 != mls_exempt)); # removed mls constraint # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 incomp h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans mlsvalidatetrans infoflow3 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # removed mls validatetrans # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 incomp l2 and h1 domby h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute added_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type added_type; type modified_remove_attr; type modified_remove_alias; type modified_remove_permissive; type modified_add_attr, an_attr; type modified_add_alias alias an_alias; type modified_add_permissive; permissive modified_add_permissive; role added_role; role modified_add_type; role modified_add_type types { system }; role modified_remove_type; # booleans bool same_bool true; bool added_bool true; bool modified_bool true; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; type added_rule_source; type added_rule_target; allow added_rule_source added_rule_target:infoflow med_w; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow { hi_r hi_w }; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow low_w; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; allow added_type self:infoflow2 med_w; type move_to_bool; bool move_to_bool_b false; if (move_to_bool_b) { allow move_to_bool self:infoflow4 hi_w; } type move_from_bool; bool move_from_bool_b false; allow move_from_bool self:infoflow4 hi_r; type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; } else { allow system switch_block:infoflow6 hi_r; allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr_A_t self:infoflow2 super_w; allow match_rule_by_attr_B_t self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_a union_perm_b:infoflow hi_w; allow union_perm_c union_perm_target:infoflow med_w; allow union_perm_source union_perm_target:infoflow low_w; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; type aa_added_rule_source; type aa_added_rule_target; auditallow aa_added_rule_source aa_added_rule_target:infoflow med_w; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow { hi_r hi_w }; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow low_w; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; auditallow added_type self:infoflow7 super_none; type aa_move_to_bool; bool aa_move_to_bool_b false; if (aa_move_to_bool_b) { auditallow aa_move_to_bool self:infoflow4 hi_w; } type aa_move_from_bool; bool aa_move_from_bool_b false; auditallow aa_move_from_bool self:infoflow4 hi_r; type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; } else { auditallow system aa_switch_block:infoflow6 hi_r; auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr_A_t self:infoflow2 super_w; auditallow aa_match_rule_by_attr_B_t self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_a aa_union_perm_b:infoflow hi_w; auditallow aa_union_perm_c aa_union_perm_target:infoflow med_w; auditallow aa_union_perm_source aa_union_perm_target:infoflow low_w; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; type da_added_rule_source; type da_added_rule_target; dontaudit da_added_rule_source da_added_rule_target:infoflow med_w; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow { hi_r hi_w }; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow low_w; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; dontaudit added_type self:infoflow7 super_none; type da_move_to_bool; bool da_move_to_bool_b false; if (da_move_to_bool_b) { dontaudit da_move_to_bool self:infoflow4 hi_w; } type da_move_from_bool; bool da_move_from_bool_b false; dontaudit da_move_from_bool self:infoflow4 hi_r; type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; } else { dontaudit system da_switch_block:infoflow6 hi_r; dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr_A_t self:infoflow2 super_w; dontaudit da_match_rule_by_attr_B_t self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_a da_union_perm_b:infoflow hi_w; dontaudit da_union_perm_c da_union_perm_target:infoflow med_w; dontaudit da_union_perm_source da_union_perm_target:infoflow low_w; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; type na_added_rule_source; type na_added_rule_target; neverallow na_added_rule_source na_added_rule_target:infoflow med_w; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow { hi_r hi_w }; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow low_w; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; neverallow added_type self:added_class new_class_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr_A_t self:infoflow2 super_w; neverallow na_match_rule_by_attr_B_t self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_a na_union_perm_b:infoflow hi_w; neverallow na_union_perm_c na_union_perm_target:infoflow med_w; neverallow na_union_perm_source na_union_perm_target:infoflow low_w; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type tt_added_rule_source; type tt_added_rule_target; type_transition tt_added_rule_source tt_added_rule_target:infoflow system; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_new_type; type_transition added_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; if (tt_move_to_bool_b) { type_transition tt_move_to_bool system:infoflow3 system; } type tt_move_from_bool; bool tt_move_from_bool_b false; type_transition tt_move_from_bool system:infoflow4 system; type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; } else { type_transition system tt_switch_block:infoflow6 system; type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type tc_added_rule_source; type tc_added_rule_target; type_change tc_added_rule_source tc_added_rule_target:infoflow system; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_new_type; type_change added_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; if (tc_move_to_bool_b) { type_change tc_move_to_bool system:infoflow3 system; } type tc_move_from_bool; bool tc_move_from_bool_b false; type_change tc_move_from_bool system:infoflow4 system; type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; } else { type_change system tc_switch_block:infoflow6 system; type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type tm_added_rule_source; type tm_added_rule_target; type_member tm_added_rule_source tm_added_rule_target:infoflow system; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_new_type; type_member added_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; if (tm_move_to_bool_b) { type_member tm_move_to_bool system:infoflow3 system; } type tm_move_from_bool; bool tm_move_from_bool_b false; type_member tm_move_from_bool system:infoflow4 system; type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; } else { type_member system tm_switch_block:infoflow6 system; type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_added_rule_source rt_added_rule_target:infoflow s3; range_transition rt_matched_source system:infoflow s0:c0,c4 - s1:c0.c2,c4; range_transition added_type system:infoflow4 s3; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #if (rt_move_to_bool_b) { #range_transition rt_move_to_bool system:infoflow3 s0; #} #type rt_move_from_bool; #bool rt_move_from_bool_b false; #range_transition rt_move_from_bool system:infoflow4 s0; #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #} else { #range_transition system rt_switch_block:infoflow6 s0; #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_B_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow added_rule_source_r added_rule_target_r; allow added_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition role_tr_added_rule_source role_tr_added_rule_target:infoflow6 system; role_transition added_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_new_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; type ax_added_rule_source; type ax_added_rule_target; allowxperm ax_added_rule_source ax_added_rule_target:infoflow ioctl 0x0002; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; allowxperm added_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; allowxperm ax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_a ax_union_perm_b:infoflow ioctl 0x1; allowxperm ax_union_perm_c ax_union_perm_target:infoflow ioctl 0x2; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl 0x3; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; type aax_added_rule_source; type aax_added_rule_target; auditallowxperm aax_added_rule_source aax_added_rule_target:infoflow ioctl 0x0002; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; auditallowxperm added_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; auditallowxperm aax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_a aax_union_perm_b:infoflow ioctl 0x1; auditallowxperm aax_union_perm_c aax_union_perm_target:infoflow ioctl 0x2; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl 0x3; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; type nax_added_rule_source; type nax_added_rule_target; neverallowxperm nax_added_rule_source nax_added_rule_target:infoflow ioctl 0x0002; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; neverallowxperm added_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; neverallowxperm nax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_a nax_union_perm_b:infoflow ioctl 0x1; neverallowxperm nax_union_perm_c nax_union_perm_target:infoflow ioctl 0x2; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl 0x3; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; type dax_added_rule_source; type dax_added_rule_target; dontauditxperm dax_added_rule_source dax_added_rule_target:infoflow ioctl 0x0002; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; dontauditxperm added_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; dontauditxperm dax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_a dax_union_perm_b:infoflow ioctl 0x1; dontauditxperm dax_union_perm_c dax_union_perm_target:infoflow ioctl 0x2; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl 0x3; ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; # added typebounds type added_parent; type added_child; typebounds added_parent added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_added mod_child; # policycaps policycap open_perms; policycap always_check_network; #users user system roles system level s0 range s0; user added_user roles system level s1 range s1; user modified_add_role roles { system added_role } level s2 range s2; user modified_remove_role roles system level s2 range s2; user modified_change_level roles system level s2:c1 range s2:c1 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c4; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint constrain infoflow3 null (u1 != u2); # removed constraint # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 != system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans validatetrans infoflow3 (t1 == t2 or t3 == system); # removed validatetrans # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 != u2 and r1 == r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid matched_sid system:system:system:s0 sid added_sid added_user:system:system:s1 sid modified_sid modified_add_role:system:system:s2 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_xattr added_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse added_user:object_r:system:s1; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon added_genfs / added_user:object_r:system:s0 genfscon change_path /new system:object_r:system:s0 genfscon modified_genfs / -s added_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # added portcons portcon udp 2024 system:object_r:system:s0 portcon tcp 2024-2026 system:object_r:system:s0 # modified portcons portcon udp 3024 added_user:object_r:system:s1 portcon tcp 3024-3026 added_user:object_r:system:s1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon added_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif added_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 added_user:object_r:system:s0 netifcon mod_both_netif added_user:object_r:system:s0 added_user:object_r:system:s0 # matched nodecons nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 # added nodecons nodecon 127.0.0.4 255.255.255.255 added_user:object_r:system:s0 nodecon ::4 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff added_user:object_r:system:s0 # modified nodecons nodecon 127.0.0.3 255.255.255.255 modified_change_level:object_r:system:s2:c0 nodecon ::3 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff modified_change_level:object_r:system:s2:c1 # change netmask (add/remove) nodecon 127.0.0.5 255.255.255.0 system:object_r:system:s0 nodecon ::5 ffff:ffff:ffff:ffff:ffff:ffff:ffff:: system:object_r:system:s0 setools-4.1.1/tests/dta.conf000066400000000000000000000130331314142262400157650ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class process class file class sock_file sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class process { transition dyntransition setexec setcurrent } class file { execute entrypoint } class sock_file { execute } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Domain transition analysis # # The extent of the valid transition graph: # # start -> trans1 -> trans2 -> trans3 -> trans5 # | # | -> dyntrans100 -> bothtrans200 # # Everything else is invalid # test 1 # type_transition start -> trans1 type start; type trans1; type trans1_exec; allow start trans1:process transition; allow start trans1_exec:file execute; allow trans1 trans1_exec:file entrypoint; type_transition start trans1_exec:process trans1; # test 2 # setexec trans1 -> trans2 type trans2; type trans2_exec; allow trans1 self:process setexec; allow trans1 trans2:process transition; allow trans1 trans2_exec:file execute; allow trans2 trans2_exec:file entrypoint; # test 3 # type_transiton and setexec trans2 -> trans3 # 2 entrypoints type trans3; type trans3_exec1; type trans3_exec2; allow trans2 self:process setexec; allow trans2 trans3:process transition; allow trans2 { trans3_exec1 trans3_exec2 }:file execute; allow trans3 { trans3_exec1 trans3_exec2 }:file entrypoint; type_transition trans2 trans3_exec1:process trans3; # test 4 # invalid transition, no type_transition/setexec type trans4; type trans4_exec; allow start trans4:process transition; allow start trans4_exec:file execute; allow trans4 trans4_exec:file entrypoint; # test 5 # type_transition trans3 -> trans5 # 1 entrypoint w/conditional type_trans # This makes sure the type_transition fully # matches as expected. type trans5; type trans5_exec; bool trans5 false; allow trans3 trans5:process transition; allow trans3 trans5_exec:file execute; allow trans5 trans5_exec:file entrypoint; if(trans5) { type_transition trans3 trans5_exec:process trans5; } else { type_transition trans3 trans5_exec:process trans4; } # test 100 # dyntrans start -> dyntrans100 type dyntrans100; allow start self:process setcurrent; allow start dyntrans100:process dyntransition; # test 101 # invalid dyntransition, no setcurrent type dyntrans101; type dyntrans102; allow dyntrans101 dyntrans102:process dyntransition; # test 200 # all transition possiblities dyntrans100 -> bothtrans200 type bothtrans200; type bothtrans200_exec; allow dyntrans100 self:process { setexec setcurrent }; allow dyntrans100 bothtrans200:process { transition dyntransition }; allow dyntrans100 bothtrans200_exec:file execute; allow bothtrans200 bothtrans200_exec:file entrypoint; type_transition dyntrans100 bothtrans200_exec:process bothtrans200; # test 201 # no loops in graph type bothtrans201; type bothtrans201_exec; allow bothtrans201 self:process { setexec setcurrent }; allow bothtrans201 bothtrans201:process { transition dyntransition }; allow bothtrans201 bothtrans201_exec:file { execute entrypoint }; # test 300 # auditallow by itself does not work for execute perms type trans300; type trans300_exec; allow start trans300:process transition; auditallow start trans300_exec:file execute; allow trans300 trans300_exec:file entrypoint; type_transition start trans300_exec:process trans300; # test 301 # wrong class for type transition type trans301; type trans301_exec; allow start trans301:process transition; allow start trans301_exec:file execute; allow trans301 trans301_exec:file entrypoint; type_transition start trans301_exec:file trans301; # test 302 # wrong class for exec perms type trans302; type trans302_exec; allow start trans302:process transition; allow start trans302_exec:sock_file execute; allow trans302 trans302_exec:file entrypoint; type_transition start trans302_exec:file trans302; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/dta.py000066400000000000000000001070671314142262400155030ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, DomainTransitionAnalysis from setools import TERuletype as TERT from setools.policyrep.exception import InvalidType from setools.policyrep.typeattr import Type from . import mixins class DomainTransitionAnalysisTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/dta.conf") cls.a = DomainTransitionAnalysis(cls.p) cls.a._build_graph() def test_000_graph_structure(self): """DTA: verify graph structure.""" # don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.G.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_001_bothtrans(self): """DTA: type_transition, setexeccon(), and setcon() transitions.""" s = self.p.lookup_type("dyntrans100") t = self.p.lookup_type("bothtrans200") e = self.p.lookup_type("bothtrans200_exec") # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition", "dyntransition"])) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec", "setcurrent"])) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t) # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition", "dyntransition"])) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec", "setcurrent"])) def test_010_dyntrans(self): """DTA: setcon() transition.""" s = self.p.lookup_type("start") t = self.p.lookup_type("dyntrans100") # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 0) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(len(k), 0) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(len(k), 0) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(len(k), 0) # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["dyntransition"])) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setcurrent"])) def test_020_trans(self): """DTA: type_transition transition.""" s = self.p.lookup_type("start") t = self.p.lookup_type("trans1") e = self.p.lookup_type("trans1_exec") # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t) # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 0) def test_030_setexec(self): """DTA: setexec() transition.""" s = self.p.lookup_type("trans1") t = self.p.lookup_type("trans2") e = self.p.lookup_type("trans2_exec") # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec"])) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(len(k), 0) # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 0) def test_040_two_entrypoint(self): """DTA: 2 entrypoints, only one by type_transition.""" s = self.p.lookup_type("trans2") t = self.p.lookup_type("trans3") e = [self.p.lookup_type("trans3_exec1"), self.p.lookup_type("trans3_exec2")] # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec"])) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(k, e) r = self.a.G.edge[s][t]["execute"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e[0], "file", set(["execute"])) r = self.a.G.edge[s][t]["execute"][e[1]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e[1], "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(k, e) r = self.a.G.edge[s][t]["entrypoint"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e[0], "file", set(["entrypoint"])) r = self.a.G.edge[s][t]["entrypoint"][e[1]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e[1], "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(k, [e[0]]) r = self.a.G.edge[s][t]["type_transition"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e[0], "process", t) # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 0) def test_050_cond_type_trans(self): """DTA: conditional type_transition.""" s = self.p.lookup_type("trans3") t = self.p.lookup_type("trans5") e = self.p.lookup_type("trans5_exec") # regular transition r = self.a.G.edge[s][t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edge[s][t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edge[s][t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edge[s][t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edge[s][t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edge[s][t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t, cond="trans5") # dynamic transition r = self.a.G.edge[s][t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edge[s][t]["setcurrent"] self.assertEqual(len(r), 0) def test_100_forward_subgraph_structure(self): """DTA: verify forward subgraph structure.""" # The purpose is to ensure the subgraph is reversed # only when the reverse option is set, not that # graph reversal is correct (assumed that NetworkX # does it correctly). # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_101_reverse_subgraph_structure(self): """DTA: verify reverse subgraph structure.""" # The purpose is to ensure the subgraph is reversed # only when the reverse option is set, not that # graph reversal is correct (assumed that NetworkX # does it correctly). # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = True self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(bothtrans200, dyntrans100), (dyntrans100, start), (trans1, start), (trans2, trans1), (trans3, trans2), (trans5, trans3)]), edges) def test_200_exclude_domain(self): """DTA: exclude domain type.""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans1"] self.a._build_subgraph() start = self.p.lookup_type("start") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (trans2, trans3), (trans3, trans5)]), edges) def test_201_exclude_entryoint_with_2entrypoints(self): """DTA: exclude entrypoint type without transition deletion (other entrypoints).""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans3_exec1"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_202_exclude_entryoint_with_dyntrans(self): """DTA: exclude entrypoint type without transition deletion (dyntrans).""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["bothtrans200_exec"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_203_exclude_entryoint_delete_transition(self): """DTA: exclude entrypoint type with transition deletion.""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans2_exec"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans2, trans3), (trans3, trans5)]), edges) def test_300_all_paths(self): """DTA: all paths output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.all_paths("start", "bothtrans200", 3)) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum+1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_301_all_shortest_paths(self): """DTA: all shortest paths output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.all_shortest_paths("start", "bothtrans200")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum+1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_302_shortest_path(self): """DTA: shortest path output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.shortest_path("start", "bothtrans200")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum+1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_303_transitions(self): """DTA: transitions output""" self.a.reverse = False self.a.exclude = None transitions = list(self.a.transitions("start")) self.assertEqual(2, len(transitions)) for step in transitions: self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual("start", step.source) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_310_all_paths_reversed(self): """DTA: all paths output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.all_paths("bothtrans200", "start", 3)) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, expected_path[stepnum+1]) self.assertEqual(step.target, expected_path[stepnum]) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_311_all_shortest_paths_reversed(self): """DTA: all shortest paths output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.all_shortest_paths("bothtrans200", "start")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, expected_path[stepnum+1]) self.assertEqual(step.target, expected_path[stepnum]) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_312_shortest_path_reversed(self): """DTA: shortest path output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.shortest_path("bothtrans200", "start")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum+1], step.source) self.assertEqual(expected_path[stepnum], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_313_transitions_reversed(self): """DTA: transitions output reverse DTA""" self.a.reverse = True self.a.exclude = None transitions = list(self.a.transitions("bothtrans200")) self.assertEqual(1, len(transitions)) for step in transitions: self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual("bothtrans200", step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_900_set_exclude_invalid_type(self): """DTA: set invalid excluded type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): self.a.exclude = ["trans1", "invalid_type"] def test_910_all_paths_invalid_source(self): """DTA: all paths with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_paths("invalid_type", "trans1")) def test_911_all_paths_invalid_target(self): """DTA: all paths with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_paths("trans1", "invalid_type")) def test_912_all_paths_invalid_maxlen(self): """DTA: all paths with invalid max path length.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(ValueError): list(self.a.all_paths("trans1", "trans2", maxlen=-2)) def test_913_all_paths_source_excluded(self): """DTA: all paths with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.all_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_914_all_paths_target_excluded(self): """DTA: all paths with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.all_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_915_all_paths_source_disconnected(self): """DTA: all paths with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.all_paths("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_916_all_paths_target_disconnected(self): """DTA: all paths with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.all_paths("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_920_shortest_path_invalid_source(self): """DTA: shortest path with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.shortest_path("invalid_type", "trans1")) def test_921_shortest_path_invalid_target(self): """DTA: shortest path with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.shortest_path("trans1", "invalid_type")) def test_922_shortest_path_source_excluded(self): """DTA: shortest path with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.shortest_path("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_923_shortest_path_target_excluded(self): """DTA: shortest path with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.shortest_path("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_924_shortest_path_source_disconnected(self): """DTA: shortest path with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.shortest_path("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_925_shortest_path_target_disconnected(self): """DTA: shortest path with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.shortest_path("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_930_all_shortest_paths_invalid_source(self): """DTA: all shortest paths with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("invalid_type", "trans1")) def test_931_all_shortest_paths_invalid_target(self): """DTA: all shortest paths with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("trans1", "invalid_type")) def test_932_all_shortest_paths_source_excluded(self): """DTA: all shortest paths with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.all_shortest_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_933_all_shortest_paths_target_excluded(self): """DTA: all shortest paths with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.all_shortest_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_934_all_shortest_paths_source_disconnected(self): """DTA: all shortest paths with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.all_shortest_paths("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_935_all_shortest_paths_target_disconnected(self): """DTA: all shortest paths with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.all_shortest_paths("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_940_transitions_invalid_source(self): """DTA: transitions with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.transitions("invalid_type")) def test_941_transitions_source_excluded(self): """DTA: transitions with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.transitions("trans1")) self.assertEqual(0, len(paths)) def test_942_transitions_source_disconnected(self): """DTA: transitions with disconnected source type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.transitions("trans5")) self.assertEqual(0, len(paths)) setools-4.1.1/tests/fsusequery.conf000066400000000000000000000123221314142262400174300ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use # test 1: # ruletype: unset # fs: test1, exact # user: unset # role: unset # type: unset # range: unset fs_use_xattr test1 system:system:system:s0:c0.c4; # test 2: # ruletype: unset # fs: test2(a|b), regex # user: unset # role: unset # type: unset # range: unset fs_use_xattr test2a system:system:system:s0:c0.c1; fs_use_xattr test2b system:system:system:s0:c2.c4; # test 10: # ruletype: ['fs_use_trans','fs_use_task'] # fs: unset # user: unset # role: unset # type: unset # range: unset fs_use_trans test10a system:system:system:s0:c0.c1; fs_use_task test10b system:system:system:s0:c2.c4; fs_use_xattr test10c system:system:system:s0:c2; # test 20: # ruletype: unset # fs: unset # user: user20, exact # role: unset # type: unset # range: unset fs_use_xattr test20 user20:system:system:s0:c0.c1; # test 21: # ruletype: unset # fs: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset fs_use_xattr test21a user21a:system:system:s0:c0.c1; fs_use_xattr test21b user21b:system:system:s0:c0.c1; fs_use_xattr test21c user21c:system:system:s0:c0.c1; # test 30: # ruletype: unset # fs: unset # user: unset # role: role30_r, exact # type: unset # range: unset fs_use_xattr test30 system:role30_r:system:s0:c0.c1; # test 31: # ruletype: unset # fs: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset fs_use_xattr test31a system:role31a_r:system:s0:c0.c1; fs_use_xattr test31b system:role31b_r:system:s0:c0.c1; fs_use_xattr test31c system:role31c_r:system:s0:c0.c1; # test 40: # ruletype: unset # fs: unset # user: unset # role: unset # type: type40 # range: unset fs_use_xattr test40 system:system:type40:s0:c0.c1; # test 41: # ruletype: unset # fs: unset # user: unset # role: unset # type: type41(b|c) # range: unset fs_use_xattr test41a system:system:type41a:s0:c0.c1; fs_use_xattr test41b system:system:type41b:s0:c0.c1; fs_use_xattr test41c system:system:type41c:s0:c0.c1; # test 50: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: equal fs_use_xattr test50 system:system:system:s0:c1 - s0:c0.c4; # test 51: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: overlap fs_use_xattr test51 system:system:system:s1:c1 - s1:c1.c3; # test 52: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: subset fs_use_xattr test52 system:system:system:s2:c1 - s2:c1.c3; # test 53: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: superset fs_use_xattr test53 system:system:system:s3:c1 - s3:c1.c3; # test 54: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: proper subset fs_use_xattr test54 system:system:system:s4:c1 - s4:c1.c3; # test 55: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: proper superset fs_use_xattr test55 system:system:system:s5:c1 - s5:c1.c3; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/fsusequery.py000066400000000000000000000212031314142262400171310ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, FSUseQuery class FSUseQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/fsusequery.conf") def test_000_unset(self): """fs_use_* query with no criteria""" # query with no parameters gets all fs_use_*. fsu = sorted(self.p.fs_uses()) q = FSUseQuery(self.p) q_fsu = sorted(q.results()) self.assertListEqual(fsu, q_fsu) def test_001_fs_exact(self): """fs_use_* query with exact fs match""" q = FSUseQuery(self.p, fs="test1", fs_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test1"], fsu) def test_002_fs_regex(self): """fs_use_* query with regex fs match""" q = FSUseQuery(self.p, fs="test2(a|b)", fs_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test2a", "test2b"], fsu) def test_010_ruletype(self): """fs_use_* query with ruletype match""" q = FSUseQuery(self.p, ruletype=['fs_use_trans', 'fs_use_task']) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test10a", "test10b"], fsu) def test_020_user_exact(self): """fs_use_* query with context user exact match""" q = FSUseQuery(self.p, user="user20", user_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test20"], fsu) def test_021_user_regex(self): """fs_use_* query with context user regex match""" q = FSUseQuery(self.p, user="user21(a|b)", user_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test21a", "test21b"], fsu) def test_030_role_exact(self): """fs_use_* query with context role exact match""" q = FSUseQuery(self.p, role="role30_r", role_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test30"], fsu) def test_031_role_regex(self): """fs_use_* query with context role regex match""" q = FSUseQuery(self.p, role="role31(a|c)_r", role_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test31a", "test31c"], fsu) def test_040_type_exact(self): """fs_use_* query with context type exact match""" q = FSUseQuery(self.p, type_="type40", type_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test40"], fsu) def test_041_type_regex(self): """fs_use_* query with context type regex match""" q = FSUseQuery(self.p, type_="type41(b|c)", type_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test41b", "test41c"], fsu) def test_050_range_exact(self): """fs_use_* query with context range exact match""" q = FSUseQuery(self.p, range_="s0:c1 - s0:c0.c4") fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test50"], fsu) def test_051_range_overlap1(self): """fs_use_* query with context range overlap match (equal)""" q = FSUseQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap2(self): """fs_use_* query with context range overlap match (subset)""" q = FSUseQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap3(self): """fs_use_* query with context range overlap match (superset)""" q = FSUseQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap4(self): """fs_use_* query with context range overlap match (overlap low level)""" q = FSUseQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap5(self): """fs_use_* query with context range overlap match (overlap high level)""" q = FSUseQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_052_range_subset1(self): """fs_use_* query with context range subset match""" q = FSUseQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test52"], fsu) def test_052_range_subset2(self): """fs_use_* query with context range subset match (equal)""" q = FSUseQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test52"], fsu) def test_053_range_superset1(self): """fs_use_* query with context range superset match""" q = FSUseQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test53"], fsu) def test_053_range_superset2(self): """fs_use_* query with context range superset match (equal)""" q = FSUseQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test53"], fsu) def test_054_range_proper_subset1(self): """fs_use_* query with context range proper subset match""" q = FSUseQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_054_range_proper_subset2(self): """fs_use_* query with context range proper subset match (equal)""" q = FSUseQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual([], fsu) def test_054_range_proper_subset3(self): """fs_use_* query with context range proper subset match (equal low only)""" q = FSUseQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_054_range_proper_subset4(self): """fs_use_* query with context range proper subset match (equal high only)""" q = FSUseQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_055_range_proper_superset1(self): """fs_use_* query with context range proper superset match""" q = FSUseQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) def test_055_range_proper_superset2(self): """fs_use_* query with context range proper superset match (equal)""" q = FSUseQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual([], fsu) def test_055_range_proper_superset3(self): """fs_use_* query with context range proper superset match (equal low)""" q = FSUseQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) def test_055_range_proper_superset4(self): """fs_use_* query with context range proper superset match (equal high)""" q = FSUseQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) setools-4.1.1/tests/genfsconquery.conf000066400000000000000000000134601314142262400201110ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon # test 1: # fs: test1, exact # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test1 / system:system:system:s0:c0.c4 # test 2: # fs: test2(a|b), regex # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test2a / system:system:system:s0:c0.c1 genfscon test2b / system:system:system:s0:c2.c4 # test 10: # fs: unset # path: /sys, exact # user: unset # role: unset # type: unset # range: unset genfscon test10 /sys system:system:system:s0:c2.c4 # test 11: # fs: unset # path: /(spam|eggs), regex # user: unset # role: unset # type: unset # range: unset genfscon test11a /spam system:system:system:s0:c2.c4 genfscon test11b /eggs system:system:system:s0:c2.c4 genfscon test11c /FAIL system:system:system:s0:c2.c4 # test 20: # fs: unset # path: unset # user: user20, exact # role: unset # type: unset # range: unset genfscon test20 / user20:system:system:s0:c0.c1 # test 21: # fs: unset # path: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset genfscon test21a / user21a:system:system:s0:c0.c1 genfscon test21b / user21b:system:system:s0:c0.c1 genfscon test21c / user21c:system:system:s0:c0.c1 # test 30: # fs: unset # path: unset # user: unset # role: role30_r, exact # type: unset # range: unset genfscon test30 / system:role30_r:system:s0:c0.c1 # test 31: # fs: unset # path: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset genfscon test31a / system:role31a_r:system:s0:c0.c1 genfscon test31b / system:role31b_r:system:s0:c0.c1 genfscon test31c / system:role31c_r:system:s0:c0.c1 # test 40: # fs: unset # path: unset # user: unset # role: unset # type: type40 # range: unset genfscon test40 / system:system:type40:s0:c0.c1 # test 41: # fs: unset # path: unset # user: unset # role: unset # type: type41(b|c) # range: unset genfscon test41a / system:system:type41a:s0:c0.c1 genfscon test41b / system:system:type41b:s0:c0.c1 genfscon test41c / system:system:type41c:s0:c0.c1 # test 50: # fs: unset # filetype: -b # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test50f / -- system:system:system:s0:c0.c4 genfscon test50b / -b system:system:system:s0:c0.c4 genfscon test50c / -c system:system:system:s0:c0.c4 genfscon test50s / -s system:system:system:s0:c0.c4 genfscon test50l / -l system:system:system:s0:c0.c4 genfscon test50p / -p system:system:system:s0:c0.c4 genfscon test50d / -d system:system:system:s0:c0.c4 # test 60: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: equal genfscon test60 / system:system:system:s0:c1 - s0:c0.c4 # test 61: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: overlap genfscon test61 / system:system:system:s1:c1 - s1:c1.c3 # test 62: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: subset genfscon test62 / system:system:system:s2:c1 - s2:c1.c3 # test 63: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: superset genfscon test63 / system:system:system:s3:c1 - s3:c1.c3 # test 64: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: proper subset genfscon test64 / system:system:system:s4:c1 - s4:c1.c3 # test 65: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: proper superset genfscon test65 / system:system:system:s5:c1 - s5:c1.c3 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/genfsconquery.py000066400000000000000000000225461314142262400176210ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest import stat from setools import SELinuxPolicy, GenfsconQuery class GenfsconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/genfsconquery.conf") def test_000_unset(self): """Genfscon query with no criteria""" # query with no parameters gets all genfs. genfs = sorted(self.p.genfscons()) q = GenfsconQuery(self.p) q_genfs = sorted(q.results()) self.assertListEqual(genfs, q_genfs) def test_001_fs_exact(self): """Genfscon query with exact fs match""" q = GenfsconQuery(self.p, fs="test1", fs_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test1"], genfs) def test_002_fs_regex(self): """Genfscon query with regex fs match""" q = GenfsconQuery(self.p, fs="test2(a|b)", fs_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test2a", "test2b"], genfs) def test_010_path_exact(self): """Genfscon query with exact path match""" q = GenfsconQuery(self.p, path="/sys", path_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test10"], genfs) def test_011_path_regex(self): """Genfscon query with regex path match""" q = GenfsconQuery(self.p, path="/(spam|eggs)", path_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test11a", "test11b"], genfs) def test_020_user_exact(self): """Genfscon query with context user exact match""" q = GenfsconQuery(self.p, user="user20", user_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test20"], genfs) def test_021_user_regex(self): """Genfscon query with context user regex match""" q = GenfsconQuery(self.p, user="user21(a|b)", user_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test21a", "test21b"], genfs) def test_030_role_exact(self): """Genfscon query with context role exact match""" q = GenfsconQuery(self.p, role="role30_r", role_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test30"], genfs) def test_031_role_regex(self): """Genfscon query with context role regex match""" q = GenfsconQuery(self.p, role="role31(a|c)_r", role_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test31a", "test31c"], genfs) def test_040_type_exact(self): """Genfscon query with context type exact match""" q = GenfsconQuery(self.p, type_="type40", type_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test40"], genfs) def test_041_type_regex(self): """Genfscon query with context type regex match""" q = GenfsconQuery(self.p, type_="type41(b|c)", type_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test41b", "test41c"], genfs) def test_050_file_type(self): """Genfscon query with file type match""" q = GenfsconQuery(self.p, filetype=stat.S_IFBLK) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test50b"], genfs) def test_060_range_exact(self): """Genfscon query with context range exact match""" q = GenfsconQuery(self.p, range_="s0:c1 - s0:c0.c4") genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test60"], genfs) def test_061_range_overlap1(self): """Genfscon query with context range overlap match (equal)""" q = GenfsconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap2(self): """Genfscon query with context range overlap match (subset)""" q = GenfsconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap3(self): """Genfscon query with context range overlap match (superset)""" q = GenfsconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap4(self): """Genfscon query with context range overlap match (overlap low level)""" q = GenfsconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap5(self): """Genfscon query with context range overlap match (overlap high level)""" q = GenfsconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_062_range_subset1(self): """Genfscon query with context range subset match""" q = GenfsconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test62"], genfs) def test_062_range_subset2(self): """Genfscon query with context range subset match (equal)""" q = GenfsconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test62"], genfs) def test_063_range_superset1(self): """Genfscon query with context range superset match""" q = GenfsconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test63"], genfs) def test_063_range_superset2(self): """Genfscon query with context range superset match (equal)""" q = GenfsconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test63"], genfs) def test_064_range_proper_subset1(self): """Genfscon query with context range proper subset match""" q = GenfsconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_064_range_proper_subset2(self): """Genfscon query with context range proper subset match (equal)""" q = GenfsconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual([], genfs) def test_064_range_proper_subset3(self): """Genfscon query with context range proper subset match (equal low only)""" q = GenfsconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_064_range_proper_subset4(self): """Genfscon query with context range proper subset match (equal high only)""" q = GenfsconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_065_range_proper_superset1(self): """Genfscon query with context range proper superset match""" q = GenfsconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) def test_065_range_proper_superset2(self): """Genfscon query with context range proper superset match (equal)""" q = GenfsconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual([], genfs) def test_065_range_proper_superset3(self): """Genfscon query with context range proper superset match (equal low)""" q = GenfsconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) def test_065_range_proper_superset4(self): """Genfscon query with context range proper superset match (equal high)""" q = GenfsconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) setools-4.1.1/tests/infoflow.conf000066400000000000000000000066341314142262400170510ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class file class process sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super } class infoflow3 { null } class file { execute entrypoint } class process { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Note: these tests should be to determine if the graph # is being constructed correctly. It is assumed that the # graph algorithms being used are correct, as they are # unit tested by the NetworkX project itself. # # # Max steps for all flows: 6 # # Graph if min weight is 8 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ # 1 -> 2-/ # # 3 5 -> 8 <-> 9 # # Graph if min weight is 3 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 5 -> 8 <-> 9 # # Graph if min weight is 1 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 -> 5 -> 8 <-> 9 # # # attribute allnodes; type node1, allnodes; type node2, allnodes; type node3, allnodes; type node4, allnodes; type node5, allnodes; type node6, allnodes; type node7, allnodes; type node8, allnodes; type node9, allnodes; # no infoflow allow allnodes allnodes:infoflow3 null; # 1->2 (10, 5) allow node1 node2:infoflow med_w; allow node2 node1:infoflow hi_r; # 1->3 (5, 1) allow node3 node1:infoflow { low_r med_r }; # 2->4 (10) allow node2 node4:infoflow hi_w; # 3->5 (1) allow node5 node3:infoflow low_r; # 4->6 (10) allow node4 node6:infoflow2 hi_w; # 6->5 (5) allow node5 node6:infoflow med_r; # 6->7 (10) allow node6 node7:infoflow hi_w; # 5->8 (10) allow node5 node8:infoflow2 hi_w; # 8 <-> 9 (10) allow node8 node9:infoflow2 super; # disconnected from the main graph # for testing the handling of no # paths. type disconnected1; type disconnected2; allow disconnected1 disconnected2:infoflow2 super; # not an infoflow: type disconnected3; auditallow node1 disconnected3:infoflow hi_w; # infoflow loop that should be ignored: allow disconnected3 self:infoflow hi_w; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/infoflow.py000066400000000000000000000461301314142262400165470ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, InfoFlowAnalysis from setools import TERuletype as TERT from setools.permmap import PermissionMap from setools.policyrep.exception import InvalidType from setools.policyrep.typeattr import Type from . import mixins # Note: the testing for having correct rules on every edge is only # performed once on the full graph, since it is assumed that NetworkX's # Digraph.subgraph() function correctly copies the edge attributes into # the subgraph. class InfoFlowAnalysisTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/infoflow.conf") cls.m = PermissionMap("tests/perm_map") cls.a = InfoFlowAnalysis(cls.p, cls.m) def test_001_full_graph(self): """Information flow analysis full graph.""" self.a._build_graph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node3 = self.p.lookup_type("node3") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") nodes = set(self.a.G.nodes_iter()) self.assertSetEqual(set([disconnected1, disconnected2, node1, node2, node3, node4, node5, node6, node7, node8, node9]), nodes) edges = set(self.a.G.out_edges_iter()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node1, node3), (node2, node4), (node3, node5), (node4, node6), (node5, node8), (node6, node5), (node6, node7), (node8, node9), (node9, node8)]), edges) r = self.a.G.edge[disconnected1][disconnected2]["rules"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "disconnected1", "disconnected2", "infoflow2", set(["super"])) r = self.a.G.edge[disconnected2][disconnected1]["rules"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "disconnected1", "disconnected2", "infoflow2", set(["super"])) r = sorted(self.a.G.edge[node1][node2]["rules"]) self.assertEqual(len(r), 2) self.validate_rule(r[0], TERT.allow, "node1", "node2", "infoflow", set(["med_w"])) self.validate_rule(r[1], TERT.allow, "node2", "node1", "infoflow", set(["hi_r"])) r = sorted(self.a.G.edge[node1][node3]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node3", "node1", "infoflow", set(["low_r", "med_r"])) r = sorted(self.a.G.edge[node2][node4]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node2", "node4", "infoflow", set(["hi_w"])) r = sorted(self.a.G.edge[node3][node5]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node3", "infoflow", set(["low_r"])) r = sorted(self.a.G.edge[node4][node6]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node4", "node6", "infoflow2", set(["hi_w"])) r = sorted(self.a.G.edge[node5][node8]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node8", "infoflow2", set(["hi_w"])) r = sorted(self.a.G.edge[node6][node5]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node6", "infoflow", set(["med_r"])) r = sorted(self.a.G.edge[node6][node7]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node6", "node7", "infoflow", set(["hi_w"])) r = sorted(self.a.G.edge[node8][node9]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node8", "node9", "infoflow2", set(["super"])) r = sorted(self.a.G.edge[node9][node8]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node8", "node9", "infoflow2", set(["super"])) def test_100_minimum_3(self): """Information flow analysis with minimum weight 3.""" self.a.exclude = None self.a.min_weight = 3 self.a._build_subgraph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node3 = self.p.lookup_type("node3") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") # don't test nodes list, as disconnected nodes # are not removed by subgraph generation. we # assume NetworkX copies into the subgraph # correctly. edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node1, node3), (node2, node4), (node4, node6), (node5, node8), (node6, node5), (node6, node7), (node8, node9), (node9, node8)]), edges) def test_200_minimum_8(self): """Information flow analysis with minimum weight 8.""" self.a.exclude = None self.a.min_weight = 8 self.a._build_subgraph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") # don't test nodes list, as disconnected nodes # are not removed by subgraph generation. we # assume NetworkX copies into the subgraph # correctly. edges = set(self.a.subG.out_edges_iter()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node2, node4), (node4, node6), (node5, node8), (node6, node7), (node8, node9), (node9, node8)]), edges) def test_300_all_paths(self): """Information flow analysis: all paths output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node4", 3)) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_301_all_shortest_paths(self): """Information flow analysis: all shortest paths output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node4")) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_302_shortest_path(self): """Information flow analysis: shortest path output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node4")) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_303_infoflows_out(self): """Information flow analysis: flows out of a type""" self.a.exclude = None self.a.min_weight = 1 for flow in self.a.infoflows("node6"): self.assertIsInstance(flow.source, Type) self.assertIsInstance(flow.target, Type) self.assertEqual(flow.source, "node6") for r in flow.rules: self.assertEqual(TERT.allow, r.ruletype) def test_304_infoflows_in(self): """Information flow analysis: flows in to a type""" self.a.exclude = None self.a.min_weight = 1 for flow in self.a.infoflows("node8", out=False): self.assertIsInstance(flow.source, Type) self.assertIsInstance(flow.target, Type) self.assertEqual(flow.target, "node8") for r in flow.rules: self.assertEqual(TERT.allow, r.ruletype) def test_900_set_exclude_invalid_type(self): """Information flow analysis: set invalid excluded type.""" with self.assertRaises(InvalidType): self.a.exclude = ["node1", "invalid_type"] def test_901_set_small_min_weight(self): """Information flow analysis: set too small weight.""" with self.assertRaises(ValueError): self.a.min_weight = 0 with self.assertRaises(ValueError): self.a.min_weight = -3 def test_902_set_large_min_weight(self): """Information flow analysis: set too big weight.""" with self.assertRaises(ValueError): self.a.min_weight = 11 with self.assertRaises(ValueError): self.a.min_weight = 50 def test_910_all_paths_invalid_source(self): """Information flow analysis: all paths with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_paths("invalid_type", "node1")) def test_911_all_paths_invalid_target(self): """Information flow analysis: all paths with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_paths("node1", "invalid_type")) def test_912_all_paths_invalid_maxlen(self): """Information flow analysis: all paths with invalid max path length.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(ValueError): list(self.a.all_paths("node1", "node2", maxlen=-2)) def test_913_all_paths_source_excluded(self): """Information flow analysis: all paths with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_914_all_paths_target_excluded(self): """Information flow analysis: all paths with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_915_all_paths_source_disconnected(self): """Information flow analysis: all paths with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_916_all_paths_target_disconnected(self): """Information flow analysis: all paths with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_920_shortest_path_invalid_source(self): """Information flow analysis: shortest path with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.shortest_path("invalid_type", "node1")) def test_921_shortest_path_invalid_target(self): """Information flow analysis: shortest path with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.shortest_path("node1", "invalid_type")) def test_922_shortest_path_source_excluded(self): """Information flow analysis: shortest path with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node2")) self.assertEqual(0, len(paths)) def test_923_shortest_path_target_excluded(self): """Information flow analysis: shortest path with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node2")) self.assertEqual(0, len(paths)) def test_924_shortest_path_source_disconnected(self): """Information flow analysis: shortest path with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_925_shortest_path_target_disconnected(self): """Information flow analysis: shortest path with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_930_all_shortest_paths_invalid_source(self): """Information flow analysis: all shortest paths with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("invalid_type", "node1")) def test_931_all_shortest_paths_invalid_target(self): """Information flow analysis: all shortest paths with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("node1", "invalid_type")) def test_932_all_shortest_paths_source_excluded(self): """Information flow analysis: all shortest paths with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_933_all_shortest_paths_target_excluded(self): """Information flow analysis: all shortest paths with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_934_all_shortest_paths_source_disconnected(self): """Information flow analysis: all shortest paths with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_935_all_shortest_paths_target_disconnected(self): """Information flow analysis: all shortest paths with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_940_infoflows_invalid_source(self): """Information flow analysis: infoflows with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.infoflows("invalid_type")) def test_941_infoflows_source_excluded(self): """Information flow analysis: infoflows with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.infoflows("node1")) self.assertEqual(0, len(paths)) def test_942_infoflows_source_disconnected(self): """Information flow analysis: infoflows with disconnected source type.""" self.a.exclude = ["disconnected2"] self.a.min_weight = 1 paths = list(self.a.infoflows("disconnected1")) self.assertEqual(0, len(paths)) setools-4.1.1/tests/initsidquery.conf000066400000000000000000000112171314142262400177500ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid test1 sid test2a sid test2b sid test10 sid test11a sid test11b sid test11c sid test20 sid test21a sid test21b sid test21c sid test30 sid test31a sid test31b sid test31c sid test40 sid test41 sid test42 sid test43 sid test44 sid test45 common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); ######################################### # # Initial SID query tests # # test 1: # name: test1, exact # user: unset # role: unset # type: unset # range: unset sid test1 system:system:system:s0:c0.c4 # test 2: # name: test2(a|b), regex # user: unset # role: unset # type: unset # range: unset sid test2a system:system:system:s0:c0.c1 sid test2b system:system:system:s0:c2.c4 # test 10: # name: unset # user: user10, exact # role: unset # type: unset # range: unset sid test10 user10:system:system:s0:c0.c1 # test 11: # name: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset sid test11a user11a:system:system:s0:c0.c1 sid test11b user11b:system:system:s0:c0.c1 sid test11c user11c:system:system:s0:c0.c1 # test 20: # name: unset # user: unset # role: role20_r, exact # type: unset # range: unset sid test20 system:role20_r:system:s0:c0.c1 # test 21: # name: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset sid test21a system:role21a_r:system:s0:c0.c1 sid test21b system:role21b_r:system:s0:c0.c1 sid test21c system:role21c_r:system:s0:c0.c1 # test 30: # name: unset # user: unset # role: unset # type: type30 # range: unset sid test30 system:system:type30:s0:c0.c1 # test 31: # name: unset # user: unset # role: unset # type: type31(b|c) # range: unset sid test31a system:system:type31a:s0:c0.c1 sid test31b system:system:type31b:s0:c0.c1 sid test31c system:system:type31c:s0:c0.c1 # test 40: # name: unset # user: unset # role: unset # type: unset # range: equal sid test40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # name: unset # user: unset # role: unset # type: unset # range: overlap sid test41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # name: unset # user: unset # role: unset # type: unset # range: subset sid test42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # name: unset # user: unset # role: unset # type: unset # range: superset sid test43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # name: unset # user: unset # role: unset # type: unset # range: proper subset sid test44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # name: unset # user: unset # role: unset # type: unset # range: proper superset sid test45 system:system:system:s5:c1 - s5:c1.c3 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/initsidquery.py000066400000000000000000000214461314142262400174600ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, InitialSIDQuery class InitialSIDQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/initsidquery.conf") def test_000_unset(self): """Initial SID query with no criteria""" # query with no parameters gets all SIDs. sids = sorted(self.p.initialsids()) q = InitialSIDQuery(self.p) q_sids = sorted(q.results()) self.assertListEqual(sids, q_sids) def test_001_name_exact(self): """Initial SID query with exact match""" q = InitialSIDQuery(self.p, name="test1", name_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test1"], sids) def test_002_name_regex(self): """Initial SID query with regex match""" q = InitialSIDQuery(self.p, name="test2(a|b)", name_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test2a", "test2b"], sids) def test_010_user_exact(self): """Initial SID query with context user exact match""" q = InitialSIDQuery(self.p, user="user10", user_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test10"], sids) def test_011_user_regex(self): """Initial SID query with context user regex match""" q = InitialSIDQuery(self.p, user="user11(a|b)", user_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test11a", "test11b"], sids) def test_020_role_exact(self): """Initial SID query with context role exact match""" q = InitialSIDQuery(self.p, role="role20_r", role_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test20"], sids) def test_021_role_regex(self): """Initial SID query with context role regex match""" q = InitialSIDQuery(self.p, role="role21(a|c)_r", role_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test21a", "test21c"], sids) def test_030_type_exact(self): """Initial SID query with context type exact match""" q = InitialSIDQuery(self.p, type_="type30", type_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test30"], sids) def test_031_type_regex(self): """Initial SID query with context type regex match""" q = InitialSIDQuery(self.p, type_="type31(b|c)", type_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test31b", "test31c"], sids) def test_040_range_exact(self): """Initial SID query with context range exact match""" q = InitialSIDQuery(self.p, range_="s0:c1 - s0:c0.c4") sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test40"], sids) def test_041_range_overlap1(self): """Initial SID query with context range overlap match (equal)""" q = InitialSIDQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test41"], sids) def test_041_range_overlap2(self): """Initial SID query with context range overlap match (subset)""" q = InitialSIDQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test41"], sids) def test_041_range_overlap3(self): """Initial SID query with context range overlap match (superset)""" q = InitialSIDQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test41"], sids) def test_041_range_overlap4(self): """Initial SID query with context range overlap match (overlap low level)""" q = InitialSIDQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test41"], sids) def test_041_range_overlap5(self): """Initial SID query with context range overlap match (overlap high level)""" q = InitialSIDQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test41"], sids) def test_042_range_subset1(self): """Initial SID query with context range subset match""" q = InitialSIDQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test42"], sids) def test_042_range_subset2(self): """Initial SID query with context range subset match (equal)""" q = InitialSIDQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test42"], sids) def test_043_range_superset1(self): """Initial SID query with context range superset match""" q = InitialSIDQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test43"], sids) def test_043_range_superset2(self): """Initial SID query with context range superset match (equal)""" q = InitialSIDQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test43"], sids) def test_044_range_proper_subset1(self): """Initial SID query with context range proper subset match""" q = InitialSIDQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test44"], sids) def test_044_range_proper_subset2(self): """Initial SID query with context range proper subset match (equal)""" q = InitialSIDQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual([], sids) def test_044_range_proper_subset3(self): """Initial SID query with context range proper subset match (equal low only)""" q = InitialSIDQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test44"], sids) def test_044_range_proper_subset4(self): """Initial SID query with context range proper subset match (equal high only)""" q = InitialSIDQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test44"], sids) def test_045_range_proper_superset1(self): """Initial SID query with context range proper superset match""" q = InitialSIDQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test45"], sids) def test_045_range_proper_superset2(self): """Initial SID query with context range proper superset match (equal)""" q = InitialSIDQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual([], sids) def test_045_range_proper_superset3(self): """Initial SID query with context range proper superset match (equal low)""" q = InitialSIDQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test45"], sids) def test_045_range_proper_superset4(self): """Initial SID query with context range proper superset match (equal high)""" q = InitialSIDQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["test45"], sids) setools-4.1.1/tests/invalid_perm_maps/000077500000000000000000000000001314142262400200375ustar00rootroot00000000000000setools-4.1.1/tests/invalid_perm_maps/bad-class-keyword000066400000000000000000000004261314142262400232770ustar00rootroot000000000000005 invalid infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/bad-perm-weight-high000066400000000000000000000004241314142262400236530ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 11 setools-4.1.1/tests/invalid_perm_maps/bad-perm-weight-low000066400000000000000000000004241314142262400235350ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w -1 setools-4.1.1/tests/invalid_perm_maps/bad-permcount000066400000000000000000000004321314142262400225210ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 INVALID null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/extra-class000066400000000000000000000004241314142262400222100ustar00rootroot000000000000004 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/extra-perms000066400000000000000000000004241314142262400222310ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/invalid-flowdir000066400000000000000000000004241314142262400230540ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r X 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/invalid-perm-weight000066400000000000000000000004311314142262400236340ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w INVALID setools-4.1.1/tests/invalid_perm_maps/negative-classcount000066400000000000000000000004251314142262400237410ustar00rootroot00000000000000-1 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/negative-permcount000066400000000000000000000004251314142262400235770ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 -1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/invalid_perm_maps/non-number-classcount000066400000000000000000000004321314142262400242150ustar00rootroot00000000000000invalid class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.1.1/tests/iomemconquery.conf000066400000000000000000000143231314142262400201140ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # mem addr: unset # user: unset # role: unset # type: unset # range: unset iomemcon 1 system:system:system:s0:c0.c1 # test 10: # mem addr: unset # user: user10, exact # role: unset # type: unset # range: unset iomemcon 10 user10:system:system:s0:c0.c1 # test 11: # mem addr: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset iomemcon 11 user11a:system:system:s0:c0.c1 iomemcon 11000 user11b:system:system:s0:c0.c1 iomemcon 11001 user11c:system:system:s0:c0.c1 # test 20: # mem addr: unset # user: unset # role: role20_r, exact # type: unset # range: unset iomemcon 20 system:role20_r:system:s0:c0.c1 # test 21: # mem addr: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset iomemcon 21 system:role21a_r:system:s0:c0.c1 iomemcon 21000 system:role21b_r:system:s0:c0.c1 iomemcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # mem addr: unset # user: unset # role: unset # type: type30 # range: unset iomemcon 30 system:system:type30:s0:c0.c1 # test 31: # mem addr: unset # user: unset # role: unset # type: type31(b|c) # range: unset iomemcon 31 system:system:type31a:s0:c0.c1 iomemcon 31000 system:system:type31b:s0:c0.c1 iomemcon 31001 system:system:type31c:s0:c0.c1 # test 40: # mem addr: unset # user: unset # role: unset # type: unset # range: equal iomemcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # mem addr: unset # user: unset # role: unset # type: unset # range: overlap iomemcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # mem addr: unset # user: unset # role: unset # type: unset # range: subset iomemcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # mem addr: unset # user: unset # role: unset # type: unset # range: superset iomemcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # mem addr: unset # user: unset # role: unset # type: unset # range: proper subset iomemcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # mem addr: unset # user: unset # role: unset # type: unset # range: proper superset iomemcon 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # mem addr: (50, 50) # user: unset # role: unset # type: unset # range: unset iomemcon 50 system:system:system:s0:c0.c1 # test 51: # mem addr: (50100, 50110) # user: unset # role: unset # type: unset # range: unset iomemcon 50100-50110 system:system:system:s0:c0.c1 # test 52: # mem addr: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset iomemcon 50200 system:system:system:s0:c0.c1 # test 53: # mem addr: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset iomemcon 50300-50310 system:system:system:s0:c0.c1 # test 54: # mem addr: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset iomemcon 50400 system:system:system:s0:c0.c1 # test 55: # mem addr: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset iomemcon 50500-50510 system:system:system:s0:c0.c1 # test 56: # mem addr: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset iomemcon 50601 system:system:system:s0:c0.c1 # test 57: # mem addr: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset iomemcon 50700-50710 system:system:system:s0:c0.c1 # test 58: # mem addr: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset iomemcon 50801 system:system:system:s0:c0.c1 # test 59: # mem addr: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset iomemcon 50901-50910 system:system:system:s0:c0.c1 # test 60: # mem addr: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60001 system:system:system:s0:c0.c1 # test 61: # mem addr: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60101-60110 system:system:system:s0:c0.c1 # test 62: # mem addr: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60200-60210 system:system:system:s0:c0.c1 # test 63: # mem addr: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60300-60310 system:system:system:s0:c0.c1 # test 64: # mem addr: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60400-60410 system:system:system:s0:c0.c1 # test 65: # mem addr: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60501-60509 system:system:system:s0:c0.c1 setools-4.1.1/tests/iomemconquery.py000066400000000000000000000424301314142262400176170ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, IomemconQuery class IomemconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/iomemconquery.conf") def test_000_unset(self): """Iomemcon query with no criteria""" # query with no parameters gets all addr. rules = sorted(self.p.iomemcons()) q = IomemconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Iomemcon query with context user exact match""" q = IomemconQuery(self.p, user="user10", user_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(10, 10)], addr) def test_011_user_regex(self): """Iomemcon query with context user regex match""" q = IomemconQuery(self.p, user="user11(a|b)", user_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], addr) def test_020_role_exact(self): """Iomemcon query with context role exact match""" q = IomemconQuery(self.p, role="role20_r", role_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(20, 20)], addr) def test_021_role_regex(self): """Iomemcon query with context role regex match""" q = IomemconQuery(self.p, role="role21(a|c)_r", role_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], addr) def test_030_type_exact(self): """Iomemcon query with context type exact match""" q = IomemconQuery(self.p, type_="type30", type_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(30, 30)], addr) def test_031_type_regex(self): """Iomemcon query with context type regex match""" q = IomemconQuery(self.p, type_="type31(b|c)", type_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], addr) def test_040_range_exact(self): """Iomemcon query with context range exact match""" q = IomemconQuery(self.p, range_="s0:c1 - s0:c0.c4") addr = sorted(p.addr for p in q.results()) self.assertListEqual([(40, 40)], addr) def test_041_range_overlap1(self): """Iomemcon query with context range overlap match (equal)""" q = IomemconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap2(self): """Iomemcon query with context range overlap match (subset)""" q = IomemconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap3(self): """Iomemcon query with context range overlap match (superset)""" q = IomemconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap4(self): """Iomemcon query with context range overlap match (overlap low level)""" q = IomemconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap5(self): """Iomemcon query with context range overlap match (overlap high level)""" q = IomemconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_042_range_subset1(self): """Iomemcon query with context range subset match""" q = IomemconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(42, 42)], addr) def test_042_range_subset2(self): """Iomemcon query with context range subset match (equal)""" q = IomemconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(42, 42)], addr) def test_043_range_superset1(self): """Iomemcon query with context range superset match""" q = IomemconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(43, 43)], addr) def test_043_range_superset2(self): """Iomemcon query with context range superset match (equal)""" q = IomemconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(43, 43)], addr) def test_044_range_proper_subset1(self): """Iomemcon query with context range proper subset match""" q = IomemconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_044_range_proper_subset2(self): """Iomemcon query with context range proper subset match (equal)""" q = IomemconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_044_range_proper_subset3(self): """Iomemcon query with context range proper subset match (equal low only)""" q = IomemconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_044_range_proper_subset4(self): """Iomemcon query with context range proper subset match (equal high only)""" q = IomemconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_045_range_proper_superset1(self): """Iomemcon query with context range proper superset match""" q = IomemconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_045_range_proper_superset2(self): """Iomemcon query with context range proper superset match (equal)""" q = IomemconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_045_range_proper_superset3(self): """Iomemcon query with context range proper superset match (equal low)""" q = IomemconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_045_range_proper_superset4(self): """Iomemcon query with context range proper superset match (equal high)""" q = IomemconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_050_single_equal(self): """Iomemcon query with single mem addr exact match""" q = IomemconQuery(self.p, addr=(50, 50)) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50, 50)], addr) def test_051_range_equal(self): """Iomemcon query with mem addr range exact match""" q = IomemconQuery(self.p, addr=(50100, 50110)) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50100, 50110)], addr) def test_052_single_subset(self): """Iomemcon query with single mem addr subset""" q = IomemconQuery(self.p, addr=(50200, 50200), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50200, 50200)], addr) def test_053_range_subset(self): """Iomemcon query with range subset""" q = IomemconQuery(self.p, addr=(50301, 50309), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50300, 50310)], addr) def test_053_range_subset_edge1(self): """Iomemcon query with range subset, equal edge case""" q = IomemconQuery(self.p, addr=(50300, 50310), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50300, 50310)], addr) def test_054_single_proper_subset(self): """Iomemcon query with single mem addr proper subset""" q = IomemconQuery( self.p, addr=(50400, 50400), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_055_range_proper_subset(self): """Iomemcon query with range proper subset""" q = IomemconQuery( self.p, addr=(50501, 50509), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_055_range_proper_subset_edge1(self): """Iomemcon query with range proper subset, equal edge case""" q = IomemconQuery( self.p, addr=(50500, 50510), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_055_range_proper_subset_edge2(self): """Iomemcon query with range proper subset, low equal edge case""" q = IomemconQuery( self.p, addr=(50500, 50509), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_055_range_proper_subset_edge3(self): """Iomemcon query with range proper subset, high equal edge case""" q = IomemconQuery( self.p, addr=(50501, 50510), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_056_single_superset(self): """Iomemcon query with single mem addr superset""" q = IomemconQuery(self.p, addr=(50600, 50602), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50601, 50601)], addr) def test_056_single_superset_edge1(self): """Iomemcon query with single mem addr superset, equal edge case""" q = IomemconQuery(self.p, addr=(50601, 50601), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50601, 50601)], addr) def test_057_range_superset(self): """Iomemcon query with range superset""" q = IomemconQuery(self.p, addr=(50700, 50711), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50700, 50710)], addr) def test_057_range_superset_edge1(self): """Iomemcon query with range superset, equal edge case""" q = IomemconQuery(self.p, addr=(50700, 50710), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50700, 50710)], addr) def test_058_single_proper_superset(self): """Iomemcon query with single mem addr proper superset""" q = IomemconQuery( self.p, addr=(50800, 50802), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_058_single_proper_superset_edge1(self): """Iomemcon query with single mem addr proper superset, equal edge case""" q = IomemconQuery( self.p, addr=(50801, 50801), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_058_single_proper_superset_edge2(self): """Iomemcon query with single mem addr proper superset, low equal edge case""" q = IomemconQuery( self.p, addr=(50801, 50802), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_058_single_proper_superset_edge3(self): """Iomemcon query with single mem addr proper superset, high equal edge case""" q = IomemconQuery( self.p, addr=(50800, 50801), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_059_range_proper_superset(self): """Iomemcon query with range proper superset""" q = IomemconQuery( self.p, addr=(50900, 50911), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_059_range_proper_superset_edge1(self): """Iomemcon query with range proper superset, equal edge case""" q = IomemconQuery( self.p, addr=(50901, 50910), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_059_range_proper_superset_edge2(self): """Iomemcon query with range proper superset, equal high mem addr edge case""" q = IomemconQuery( self.p, addr=(50900, 50910), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_059_range_proper_superset_edge3(self): """Iomemcon query with range proper superset, equal low mem addr edge case""" q = IomemconQuery( self.p, addr=(50901, 50911), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_060_single_overlap(self): """Iomemcon query with single overlap""" q = IomemconQuery(self.p, addr=(60001, 60001), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge1(self): """Iomemcon query with single overlap, range match low""" q = IomemconQuery(self.p, addr=(60001, 60002), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge2(self): """Iomemcon query with single overlap, range match high""" q = IomemconQuery(self.p, addr=(60000, 60001), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge3(self): """Iomemcon query with single overlap, range match proper superset""" q = IomemconQuery(self.p, addr=(60000, 60002), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_061_range_overlap_low_half(self): """Iomemcon query with range overlap, low half match""" q = IomemconQuery(self.p, addr=(60100, 60105), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60101, 60110)], addr) def test_062_range_overlap_high_half(self): """Iomemcon query with range overlap, high half match""" q = IomemconQuery(self.p, addr=(60205, 60211), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60200, 60210)], addr) def test_063_range_overlap_middle(self): """Iomemcon query with range overlap, middle match""" q = IomemconQuery(self.p, addr=(60305, 60308), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60300, 60310)], addr) def test_064_range_overlap_equal(self): """Iomemcon query with range overlap, equal match""" q = IomemconQuery(self.p, addr=(60400, 60410), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60400, 60410)], addr) def test_065_range_overlap_superset(self): """Iomemcon query with range overlap, superset match""" q = IomemconQuery(self.p, addr=(60500, 60510), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60501, 60509)], addr) setools-4.1.1/tests/ioportconquery.conf000066400000000000000000000142371314142262400203260ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # ports: unset # user: unset # role: unset # type: unset # range: unset ioportcon 1 system:system:system:s0:c0.c1 # test 10: # ports: unset # user: user10, exact # role: unset # type: unset # range: unset ioportcon 10 user10:system:system:s0:c0.c1 # test 11: # ports: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset ioportcon 11 user11a:system:system:s0:c0.c1 ioportcon 11000 user11b:system:system:s0:c0.c1 ioportcon 11001 user11c:system:system:s0:c0.c1 # test 20: # ports: unset # user: unset # role: role20_r, exact # type: unset # range: unset ioportcon 20 system:role20_r:system:s0:c0.c1 # test 21: # ports: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset ioportcon 21 system:role21a_r:system:s0:c0.c1 ioportcon 21000 system:role21b_r:system:s0:c0.c1 ioportcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # ports: unset # user: unset # role: unset # type: type30 # range: unset ioportcon 30 system:system:type30:s0:c0.c1 # test 31: # ports: unset # user: unset # role: unset # type: type31(b|c) # range: unset ioportcon 31 system:system:type31a:s0:c0.c1 ioportcon 31000 system:system:type31b:s0:c0.c1 ioportcon 31001 system:system:type31c:s0:c0.c1 # test 40: # ports: unset # user: unset # role: unset # type: unset # range: equal ioportcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # ports: unset # user: unset # role: unset # type: unset # range: overlap ioportcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # ports: unset # user: unset # role: unset # type: unset # range: subset ioportcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # ports: unset # user: unset # role: unset # type: unset # range: superset ioportcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # ports: unset # user: unset # role: unset # type: unset # range: proper subset ioportcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # ports: unset # user: unset # role: unset # type: unset # range: proper superset ioportcon 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # ports: (50, 50) # user: unset # role: unset # type: unset # range: unset ioportcon 50 system:system:system:s0:c0.c1 # test 51: # ports: (50100, 50110) # user: unset # role: unset # type: unset # range: unset ioportcon 50100-50110 system:system:system:s0:c0.c1 # test 52: # ports: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset ioportcon 50200 system:system:system:s0:c0.c1 # test 53: # ports: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset ioportcon 50300-50310 system:system:system:s0:c0.c1 # test 54: # ports: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset ioportcon 50400 system:system:system:s0:c0.c1 # test 55: # ports: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset ioportcon 50500-50510 system:system:system:s0:c0.c1 # test 56: # ports: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset ioportcon 50601 system:system:system:s0:c0.c1 # test 57: # ports: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset ioportcon 50700-50710 system:system:system:s0:c0.c1 # test 58: # ports: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset ioportcon 50801 system:system:system:s0:c0.c1 # test 59: # ports: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset ioportcon 50901-50910 system:system:system:s0:c0.c1 # test 60: # ports: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60001 system:system:system:s0:c0.c1 # test 61: # ports: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60101-60110 system:system:system:s0:c0.c1 # test 62: # ports: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60200-60210 system:system:system:s0:c0.c1 # test 63: # ports: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60300-60310 system:system:system:s0:c0.c1 # test 64: # ports: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60400-60410 system:system:system:s0:c0.c1 # test 65: # ports: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60501-60509 system:system:system:s0:c0.c1 setools-4.1.1/tests/ioportconquery.py000066400000000000000000000430241314142262400200250ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, IoportconQuery class IoportconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/ioportconquery.conf") def test_000_unset(self): """Ioportcon query with no criteria""" # query with no parameters gets all ports. rules = sorted(self.p.ioportcons()) q = IoportconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Portcon query with context user exact match""" q = IoportconQuery(self.p, user="user10", user_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(10, 10)], ports) def test_011_user_regex(self): """Portcon query with context user regex match""" q = IoportconQuery(self.p, user="user11(a|b)", user_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], ports) def test_020_role_exact(self): """Portcon query with context role exact match""" q = IoportconQuery(self.p, role="role20_r", role_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(20, 20)], ports) def test_021_role_regex(self): """Portcon query with context role regex match""" q = IoportconQuery(self.p, role="role21(a|c)_r", role_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], ports) def test_030_type_exact(self): """Portcon query with context type exact match""" q = IoportconQuery(self.p, type_="type30", type_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(30, 30)], ports) def test_031_type_regex(self): """Portcon query with context type regex match""" q = IoportconQuery(self.p, type_="type31(b|c)", type_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], ports) def test_040_range_exact(self): """Portcon query with context range exact match""" q = IoportconQuery(self.p, range_="s0:c1 - s0:c0.c4") ports = sorted(p.ports for p in q.results()) self.assertListEqual([(40, 40)], ports) def test_041_range_overlap1(self): """Portcon query with context range overlap match (equal)""" q = IoportconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap2(self): """Portcon query with context range overlap match (subset)""" q = IoportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap3(self): """Portcon query with context range overlap match (superset)""" q = IoportconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap4(self): """Portcon query with context range overlap match (overlap low level)""" q = IoportconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap5(self): """Portcon query with context range overlap match (overlap high level)""" q = IoportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_042_range_subset1(self): """Portcon query with context range subset match""" q = IoportconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_042_range_subset2(self): """Portcon query with context range subset match (equal)""" q = IoportconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_043_range_superset1(self): """Portcon query with context range superset match""" q = IoportconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_043_range_superset2(self): """Portcon query with context range superset match (equal)""" q = IoportconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_044_range_proper_subset1(self): """Portcon query with context range proper subset match""" q = IoportconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset2(self): """Portcon query with context range proper subset match (equal)""" q = IoportconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_044_range_proper_subset3(self): """Portcon query with context range proper subset match (equal low only)""" q = IoportconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset4(self): """Portcon query with context range proper subset match (equal high only)""" q = IoportconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_045_range_proper_superset1(self): """Portcon query with context range proper superset match""" q = IoportconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset2(self): """Portcon query with context range proper superset match (equal)""" q = IoportconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_045_range_proper_superset3(self): """Portcon query with context range proper superset match (equal low)""" q = IoportconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset4(self): """Portcon query with context range proper superset match (equal high)""" q = IoportconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_050_single_equal(self): """Portcon query with single port exact match""" q = IoportconQuery(self.p, ports=(50, 50)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50, 50)], ports) def test_051_range_equal(self): """Portcon query with port range exact match""" q = IoportconQuery(self.p, ports=(50100, 50110)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50100, 50110)], ports) def test_052_single_subset(self): """Portcon query with single port subset""" q = IoportconQuery(self.p, ports=(50200, 50200), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50200, 50200)], ports) def test_053_range_subset(self): """Portcon query with range subset""" q = IoportconQuery(self.p, ports=(50301, 50309), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_053_range_subset_edge1(self): """Portcon query with range subset, equal edge case""" q = IoportconQuery(self.p, ports=(50300, 50310), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_054_single_proper_subset(self): """Portcon query with single port proper subset""" q = IoportconQuery( self.p, ports=(50400, 50400), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset(self): """Portcon query with range proper subset""" q = IoportconQuery( self.p, ports=(50501, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge1(self): """Portcon query with range proper subset, equal edge case""" q = IoportconQuery( self.p, ports=(50500, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset_edge2(self): """Portcon query with range proper subset, low equal edge case""" q = IoportconQuery( self.p, ports=(50500, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge3(self): """Portcon query with range proper subset, high equal edge case""" q = IoportconQuery( self.p, ports=(50501, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_056_single_superset(self): """Portcon query with single port superset""" q = IoportconQuery(self.p, ports=(50600, 50602), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_056_single_superset_edge1(self): """Portcon query with single port superset, equal edge case""" q = IoportconQuery(self.p, ports=(50601, 50601), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_057_range_superset(self): """Portcon query with range superset""" q = IoportconQuery(self.p, ports=(50700, 50711), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_057_range_superset_edge1(self): """Portcon query with range superset, equal edge case""" q = IoportconQuery(self.p, ports=(50700, 50710), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_058_single_proper_superset(self): """Portcon query with single port proper superset""" q = IoportconQuery( self.p, ports=(50800, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge1(self): """Portcon query with single port proper superset, equal edge case""" q = IoportconQuery( self.p, ports=(50801, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_058_single_proper_superset_edge2(self): """Portcon query with single port proper superset, low equal edge case""" q = IoportconQuery( self.p, ports=(50801, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge3(self): """Portcon query with single port proper superset, high equal edge case""" q = IoportconQuery( self.p, ports=(50800, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_059_range_proper_superset(self): """Portcon query with range proper superset""" q = IoportconQuery( self.p, ports=(50900, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge1(self): """Portcon query with range proper superset, equal edge case""" q = IoportconQuery( self.p, ports=(50901, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_059_range_proper_superset_edge2(self): """Portcon query with range proper superset, equal high port edge case""" q = IoportconQuery( self.p, ports=(50900, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge3(self): """Portcon query with range proper superset, equal low port edge case""" q = IoportconQuery( self.p, ports=(50901, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_060_single_overlap(self): """Portcon query with single overlap""" q = IoportconQuery(self.p, ports=(60001, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge1(self): """Portcon query with single overlap, range match low""" q = IoportconQuery(self.p, ports=(60001, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge2(self): """Portcon query with single overlap, range match high""" q = IoportconQuery(self.p, ports=(60000, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge3(self): """Portcon query with single overlap, range match proper superset""" q = IoportconQuery(self.p, ports=(60000, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_061_range_overlap_low_half(self): """Portcon query with range overlap, low half match""" q = IoportconQuery(self.p, ports=(60100, 60105), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60101, 60110)], ports) def test_062_range_overlap_high_half(self): """Portcon query with range overlap, high half match""" q = IoportconQuery(self.p, ports=(60205, 60211), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60200, 60210)], ports) def test_063_range_overlap_middle(self): """Portcon query with range overlap, middle match""" q = IoportconQuery(self.p, ports=(60305, 60308), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60300, 60310)], ports) def test_064_range_overlap_equal(self): """Portcon query with range overlap, equal match""" q = IoportconQuery(self.p, ports=(60400, 60410), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60400, 60410)], ports) def test_065_range_overlap_superset(self): """Portcon query with range overlap, superset match""" q = IoportconQuery(self.p, ports=(60500, 60510), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60501, 60509)], ports) setools-4.1.1/tests/mixins.py000066400000000000000000000037601314142262400162350ustar00rootroot00000000000000"""Unit test mixin classes.""" # Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # # pylint: disable=too-few-public-methods import unittest from setools.policyrep.exception import RuleNotConditional, RuleUseError class ValidateRule(unittest.TestCase): """Mixin for validating policy rules.""" def validate_rule(self, rule, ruletype, source, target, tclass, last_item, cond=None, cond_block=None, xperm=None): """Validate a rule.""" self.assertEqual(ruletype, rule.ruletype) self.assertEqual(source, rule.source) self.assertEqual(target, rule.target) self.assertEqual(tclass, rule.tclass) try: # This is the common case. self.assertSetEqual(last_item, rule.perms) except (AttributeError, RuleUseError): self.assertEqual(last_item, rule.default) if cond: self.assertEqual(cond, rule.conditional) else: self.assertRaises(RuleNotConditional, getattr, rule, "conditional") if cond_block is not None: self.assertEqual(cond_block, rule.conditional_block) if xperm: self.assertEqual(xperm, rule.xperm_type) self.assertTrue(rule.extended) else: self.assertRaises(AttributeError, getattr, rule, "xperm_type") self.assertFalse(rule.extended) setools-4.1.1/tests/mlsrulequery.conf000066400000000000000000000162461314142262400177770ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s46; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c0.c4; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s46:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # TE Rule Query # # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # range: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; range_transition test1a test1t:infoflow s0; range_transition test1FAIL test1FAIL:infoflow s1; # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # range: unset attribute test2a; type test2s, test2a; type test2t; range_transition test2a test2t:infoflow s0; #range_transition test2s test2t:infoflow s1; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # range: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; range_transition test3s test3t:infoflow s1; range_transition test3aS test3t:infoflow2 s2; range_transition test3b test3t:infoflow s3; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # range: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; range_transition test4a1 test4a1:infoflow s1; range_transition test4a2 test4a2:infoflow2 s2; range_transition test4FAIL test4FAIL:infoflow s3; # test 5 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with source criteria that is an attribute, indirect match # # ruletype: unset # source: test5b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test5a; attribute test5b; type test5t1, test5a, test5b; type test5t2, test5b; type test5target; range_transition test5t1 test5target:infoflow s1; range_transition test5t2 test5target:infoflow7 s2; # test 10 # ruletype: unset # source: unset # target: test10a, direct, no regex # class: unset # range: unset attribute test10a; type test10s; type test10t, test10a; range_transition test10s test10a:infoflow s0; range_transition test10s test10t:infoflow2 s1; # test 11 # ruletype: unset # source: unset # target: test11t, indirect, no regex # class: unset # range: unset attribute test11a; type test11s; type test11t, test11a; range_transition test11s test11a:infoflow s0; range_transition test11s test11t:infoflow2 s1; # test 12 # ruletype: unset # source: unset # target: test12a.*, direct, regex # class: unset # range: unset attribute test12aPASS; attribute test12b; type test12s; type test12t, test12aPASS; type test12aFAIL, test12b; range_transition test12s test12t:infoflow s0; range_transition test12s test12aPASS:infoflow2 s1; range_transition test12s test12b:infoflow s2; # test 13 # ruletype: unset # source: unset # target: test13(s|t), indirect, regex # class: unset # range: unset attribute test13a1; attribute test13a2; type test13s1, test13a1; type test13t1, test13a2; type test13FAIL; range_transition test13a1 test13a1:infoflow s0; range_transition test13a2 test13a2:infoflow s1; range_transition test13FAIL test13FAIL:infoflow s2; # test 14 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with target criteria that is an attribute, indirect match # # ruletype: unset # source: test14b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test14a; attribute test14b; type test14t1, test14a, test14b; type test14t2, test14b; type test14source; range_transition test14source test14t1:infoflow s1; range_transition test14source test14t2:infoflow7 s2; # test 20 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # range: unset type test20; range_transition test20 test20:infoflow s0; range_transition test20 test20:infoflow7 s1; # test 21 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # range: unset type test21; range_transition test21 test21:infoflow s0; range_transition test21 test21:infoflow4 s1; range_transition test21 test21:infoflow3 s2; # test 22 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # range: unset type test22; range_transition test22 test22:infoflow s0; range_transition test22 test22:infoflow5 s1; range_transition test22 test22:infoflow6 s2; # test 40: # ruletype: unset # source: unset # target: unset # class: unset # range: equal type test40; range_transition test40 test40:infoflow s40:c1 - s40:c0.c4; # test 41: # ruletype: unset # source: unset # target: unset # class: unset # range: overlap type test41; range_transition test41 test41:infoflow s41:c1 - s41:c1.c3; # test 42: # ruletype: unset # source: unset # target: unset # class: unset # range: subset type test42; range_transition test42 test42:infoflow s42:c1 - s42:c1.c3; # test 43: # ruletype: unset # source: unset # target: unset # class: unset # range: superset type test43; range_transition test43 test43:infoflow s43:c1 - s43:c1.c3; # test 44: # ruletype: unset # source: unset # target: unset # class: unset # range: proper subset type test44; range_transition test44 test44:infoflow s44:c1 - s44:c1.c3; # test 45: # ruletype: unset # source: unset # target: unset # class: unset # range: proper superset type test45; range_transition test45 test45:infoflow s45:c1 - s45:c1.c3; ################################################################################ #users user system roles system level s0 range s0 - s46:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/mlsrulequery.py000066400000000000000000000313331314142262400174740ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, MLSRuleQuery from setools import MLSRuletype as RT from . import mixins # Note: the test policy has been written assuming range_transition # statements could have attributes. However, range_transition # statements are always expanded, so the below unit tests # have been adjusted to this fact (hence a "FAIL" in one of the # expected type names) class MLSRuleQueryTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/mlsrulequery.conf") def test_000_unset(self): """MLS rule query with no criteria.""" # query with no parameters gets all MLS rules. rules = sorted(self.p.mlsrules()) q = MLSRuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """MLS rule query with exact, direct, source match.""" q = MLSRuleQuery( self.p, source="test1s", source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test1s", "test1t", "infoflow", "s0") def test_003_source_direct_regex(self): """MLS rule query with regex, direct, source match.""" q = MLSRuleQuery( self.p, source="test3(s|aS)", source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test3s", "test3t", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test3s", "test3t", "infoflow2", "s2") def test_005_issue111(self): """MLS rule query with attribute source criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = MLSRuleQuery(self.p, source="test5b", source_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test5t1", "test5target", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test5t2", "test5target", "infoflow7", "s2") def test_010_target_direct(self): """MLS rule query with exact, direct, target match.""" q = MLSRuleQuery( self.p, target="test10t", target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test10s", "test10t", "infoflow", "s0") self.validate_rule(r[1], RT.range_transition, "test10s", "test10t", "infoflow2", "s1") def test_012_target_direct_regex(self): """MLS rule query with regex, direct, target match.""" q = MLSRuleQuery( self.p, target="test12a.*", target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test12s", "test12aFAIL", "infoflow", "s2") def test_014_issue111(self): """MLS rule query with attribute target criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = MLSRuleQuery(self.p, target="test14b", target_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test14source", "test14t1", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test14source", "test14t2", "infoflow7", "s2") @unittest.skip("Setting tclass to a string is no longer supported.") def test_020_class(self): """MLS rule query with exact object class match.""" q = MLSRuleQuery(self.p, tclass="infoflow7", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test20", "test20", "infoflow7", "s1") def test_021_class_list(self): """MLS rule query with object class list match.""" q = MLSRuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test21", "test21", "infoflow3", "s2") self.validate_rule(r[1], RT.range_transition, "test21", "test21", "infoflow4", "s1") def test_022_class_regex(self): """MLS rule query with object class regex match.""" q = MLSRuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test22", "test22", "infoflow5", "s1") self.validate_rule(r[1], RT.range_transition, "test22", "test22", "infoflow6", "s2") def test_040_range_exact(self): """MLS rule query with context range exact match""" q = MLSRuleQuery(self.p, default="s40:c1 - s40:c0.c4") r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test40", "test40", "infoflow", "s40:c1 - s40:c0.c4") def test_041_range_overlap1(self): """MLS rule query with context range overlap match (equal)""" q = MLSRuleQuery(self.p, default="s41:c1 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap2(self): """MLS rule query with context range overlap match (subset)""" q = MLSRuleQuery(self.p, default="s41:c1,c2 - s41:c0.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap3(self): """MLS rule query with context range overlap match (superset)""" q = MLSRuleQuery(self.p, default="s41 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap4(self): """MLS rule query with context range overlap match (overlap low level)""" q = MLSRuleQuery(self.p, default="s41 - s41:c1,c2", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap5(self): """MLS rule query with context range overlap match (overlap high level)""" q = MLSRuleQuery(self.p, default="s41:c1,c2 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_042_range_subset1(self): """MLS rule query with context range subset match""" q = MLSRuleQuery(self.p, default="s42:c1,c2 - s42:c0.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test42", "test42", "infoflow", "s42:c1 - s42:c1.c3") def test_042_range_subset2(self): """MLS rule query with context range subset match (equal)""" q = MLSRuleQuery(self.p, default="s42:c1 - s42:c1.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test42", "test42", "infoflow", "s42:c1 - s42:c1.c3") def test_043_range_superset1(self): """MLS rule query with context range superset match""" q = MLSRuleQuery(self.p, default="s43 - s43:c0.c4", default_superset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test43", "test43", "infoflow", "s43:c1 - s43:c1.c3") def test_043_range_superset2(self): """MLS rule query with context range superset match (equal)""" q = MLSRuleQuery(self.p, default="s43:c1 - s43:c1.c3", default_superset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test43", "test43", "infoflow", "s43:c1 - s43:c1.c3") def test_044_range_proper_subset1(self): """MLS rule query with context range proper subset match""" q = MLSRuleQuery(self.p, default="s44:c1,c2", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_044_range_proper_subset2(self): """MLS rule query with context range proper subset match (equal)""" q = MLSRuleQuery(self.p, default="s44:c1 - s44:c1.c3", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 0) def test_044_range_proper_subset3(self): """MLS rule query with context range proper subset match (equal low only)""" q = MLSRuleQuery(self.p, default="s44:c1 - s44:c1.c2", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_044_range_proper_subset4(self): """MLS rule query with context range proper subset match (equal high only)""" q = MLSRuleQuery(self.p, default="s44:c1,c2 - s44:c1.c3", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_045_range_proper_superset1(self): """MLS rule query with context range proper superset match""" q = MLSRuleQuery(self.p, default="s45 - s45:c0.c4", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_045_range_proper_superset2(self): """MLS rule query with context range proper superset match (equal)""" q = MLSRuleQuery(self.p, default="s45:c1 - s45:c1.c3", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 0) def test_045_range_proper_superset3(self): """MLS rule query with context range proper superset match (equal low)""" q = MLSRuleQuery(self.p, default="s45:c1 - s45:c1.c4", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_045_range_proper_superset4(self): """MLS rule query with context range proper superset match (equal high)""" q = MLSRuleQuery(self.p, default="s45 - s45:c1.c3", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_900_invalid_ruletype(self): """MLS rule query with invalid rule type.""" with self.assertRaises(KeyError): q = MLSRuleQuery(self.p, ruletype=["type_transition"]) setools-4.1.1/tests/netifconquery.conf000066400000000000000000000120311314142262400201050ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 # test 1: # name: test1, exact # user: unset # role: unset # type: unset # range: unset netifcon test1 system:system:system:s0:c0.c4 system:object_r:system:s0 # test 2: # name: test2(a|b), regex # user: unset # role: unset # type: unset # range: unset netifcon test2a system:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test2b system:system:system:s0:c2.c4 system:object_r:system:s0 # test 10: # name: unset # user: user10, exact # role: unset # type: unset # range: unset netifcon test10 user10:system:system:s0:c0.c1 system:object_r:system:s0 # test 11: # name: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset netifcon test11a user11a:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test11b user11b:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test11c user11c:system:system:s0:c0.c1 system:object_r:system:s0 # test 20: # name: unset # user: unset # role: role20_r, exact # type: unset # range: unset netifcon test20 system:role20_r:system:s0:c0.c1 system:object_r:system:s0 # test 21: # name: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset netifcon test21a system:role21a_r:system:s0:c0.c1 system:object_r:system:s0 netifcon test21b system:role21b_r:system:s0:c0.c1 system:object_r:system:s0 netifcon test21c system:role21c_r:system:s0:c0.c1 system:object_r:system:s0 # test 30: # name: unset # user: unset # role: unset # type: type30 # range: unset netifcon test30 system:system:type30:s0:c0.c1 system:object_r:system:s0 # test 31: # name: unset # user: unset # role: unset # type: type31(b|c) # range: unset netifcon test31a system:system:type31a:s0:c0.c1 system:object_r:system:s0 netifcon test31b system:system:type31b:s0:c0.c1 system:object_r:system:s0 netifcon test31c system:system:type31c:s0:c0.c1 system:object_r:system:s0 # test 40: # name: unset # user: unset # role: unset # type: unset # range: equal netifcon test40 system:system:system:s0:c1 - s0:c0.c4 system:object_r:system:s0 # test 41: # name: unset # user: unset # role: unset # type: unset # range: overlap netifcon test41 system:system:system:s1:c1 - s1:c1.c3 system:object_r:system:s0 # test 42: # name: unset # ruletype: unset # user: unset # role: unset # type: unset # range: subset netifcon test42 system:system:system:s2:c1 - s2:c1.c3 system:object_r:system:s0 # test 43: # name: unset # user: unset # role: unset # type: unset # range: superset netifcon test43 system:system:system:s3:c1 - s3:c1.c3 system:object_r:system:s0 # test 44: # name: unset # user: unset # role: unset # type: unset # range: proper subset netifcon test44 system:system:system:s4:c1 - s4:c1.c3 system:object_r:system:s0 # test 45: # name: unset # user: unset # role: unset # type: unset # range: proper superset netifcon test45 system:system:system:s5:c1 - s5:c1.c3 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/netifconquery.py000066400000000000000000000213541314142262400176200ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, NetifconQuery class NetifconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/netifconquery.conf") def test_000_unset(self): """Netifcon query with no criteria""" # query with no parameters gets all netifs. netifs = sorted(self.p.netifcons()) q = NetifconQuery(self.p) q_netifs = sorted(q.results()) self.assertListEqual(netifs, q_netifs) def test_001_name_exact(self): """Netifcon query with exact match""" q = NetifconQuery(self.p, name="test1", name_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test1"], netifs) def test_002_name_regex(self): """Netifcon query with regex match""" q = NetifconQuery(self.p, name="test2(a|b)", name_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test2a", "test2b"], netifs) def test_010_user_exact(self): """Netifcon query with context user exact match""" q = NetifconQuery(self.p, user="user10", user_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test10"], netifs) def test_011_user_regex(self): """Netifcon query with context user regex match""" q = NetifconQuery(self.p, user="user11(a|b)", user_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test11a", "test11b"], netifs) def test_020_role_exact(self): """Netifcon query with context role exact match""" q = NetifconQuery(self.p, role="role20_r", role_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test20"], netifs) def test_021_role_regex(self): """Netifcon query with context role regex match""" q = NetifconQuery(self.p, role="role21(a|c)_r", role_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test21a", "test21c"], netifs) def test_030_type_exact(self): """Netifcon query with context type exact match""" q = NetifconQuery(self.p, type_="type30", type_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test30"], netifs) def test_031_type_regex(self): """Netifcon query with context type regex match""" q = NetifconQuery(self.p, type_="type31(b|c)", type_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test31b", "test31c"], netifs) def test_040_range_exact(self): """Netifcon query with context range exact match""" q = NetifconQuery(self.p, range_="s0:c1 - s0:c0.c4") netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test40"], netifs) def test_041_range_overlap1(self): """Netifcon query with context range overlap match (equal)""" q = NetifconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap2(self): """Netifcon query with context range overlap match (subset)""" q = NetifconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap3(self): """Netifcon query with context range overlap match (superset)""" q = NetifconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap4(self): """Netifcon query with context range overlap match (overlap low level)""" q = NetifconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap5(self): """Netifcon query with context range overlap match (overlap high level)""" q = NetifconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_042_range_subset1(self): """Netifcon query with context range subset match""" q = NetifconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test42"], netifs) def test_042_range_subset2(self): """Netifcon query with context range subset match (equal)""" q = NetifconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test42"], netifs) def test_043_range_superset1(self): """Netifcon query with context range superset match""" q = NetifconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test43"], netifs) def test_043_range_superset2(self): """Netifcon query with context range superset match (equal)""" q = NetifconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test43"], netifs) def test_044_range_proper_subset1(self): """Netifcon query with context range proper subset match""" q = NetifconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_044_range_proper_subset2(self): """Netifcon query with context range proper subset match (equal)""" q = NetifconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual([], netifs) def test_044_range_proper_subset3(self): """Netifcon query with context range proper subset match (equal low only)""" q = NetifconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_044_range_proper_subset4(self): """Netifcon query with context range proper subset match (equal high only)""" q = NetifconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_045_range_proper_superset1(self): """Netifcon query with context range proper superset match""" q = NetifconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) def test_045_range_proper_superset2(self): """Netifcon query with context range proper superset match (equal)""" q = NetifconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual([], netifs) def test_045_range_proper_superset3(self): """Netifcon query with context range proper superset match (equal low)""" q = NetifconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) def test_045_range_proper_superset4(self): """Netifcon query with context range proper superset match (equal high)""" q = NetifconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) setools-4.1.1/tests/nodeconquery.conf000066400000000000000000000124251314142262400177340ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 # test 20: # network: unset # user: user20, exact # role: unset # type: unset # range: unset nodecon 10.1.20.1 255.255.255.255 user20:system:system:s0:c0.c1 # test 21: # network: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset nodecon 10.1.21.1 255.255.255.255 user21a:system:system:s0:c0.c1 nodecon 10.1.21.2 255.255.255.255 user21b:system:system:s0:c0.c1 nodecon 10.1.21.3 255.255.255.255 user21c:system:system:s0:c0.c1 # test 30: # network: unset # user: unset # role: role30_r, exact # type: unset # range: unset nodecon 10.1.30.1 255.255.255.255 system:role30_r:system:s0:c0.c1 # test 31: # network: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset nodecon 10.1.31.1 255.255.255.255 system:role31a_r:system:s0:c0.c1 nodecon 10.1.31.2 255.255.255.255 system:role31b_r:system:s0:c0.c1 nodecon 10.1.31.3 255.255.255.255 system:role31c_r:system:s0:c0.c1 # test 40: # network: unset # user: unset # role: unset # type: type40 # range: unset nodecon 10.1.40.1 255.255.255.255 system:system:type40:s0:c0.c1 # test 41: # network: unset # user: unset # role: unset # type: type41(b|c) # range: unset nodecon 10.1.41.1 255.255.255.255 system:system:type41a:s0:c0.c1 nodecon 10.1.41.2 255.255.255.255 system:system:type41b:s0:c0.c1 nodecon 10.1.41.3 255.255.255.255 system:system:type41c:s0:c0.c1 # test 50: # network: unset # user: unset # role: unset # type: unset # range: equal nodecon 10.1.50.1 255.255.255.255 system:system:system:s0:c1 - s0:c0.c4 # test 51: # network: unset # user: unset # role: unset # type: unset # range: overlap nodecon 10.1.51.1 255.255.255.255 system:system:system:s1:c1 - s1:c1.c3 # test 52: # network: unset # user: unset # role: unset # type: unset # range: subset nodecon 10.1.52.1 255.255.255.255 system:system:system:s2:c1 - s2:c1.c3 # test 53: # network: unset # user: unset # role: unset # type: unset # range: superset nodecon 10.1.53.1 255.255.255.255 system:system:system:s3:c1 - s3:c1.c3 # test 54: # network: unset # user: unset # role: unset # type: unset # range: proper subset nodecon 10.1.54.1 255.255.255.255 system:system:system:s4:c1 - s4:c1.c3 # test 55: # network: unset # user: unset # role: unset # type: unset # range: proper superset nodecon 10.1.55.1 255.255.255.255 system:system:system:s5:c1 - s5:c1.c3 # test 100: # network: 10.1.100.0/24, equal # user: unset # role: unset # type: unset # range: unset nodecon 10.1.100.0 255.255.255.0 system:system:system:s0:c0.c1 # test 101: # network: 10.1.101.128/25, overlap # user: unset # role: unset # type: unset # range: unset nodecon 10.1.101.0 255.255.255.0 system:system:system:s0:c0.c1 # test 110: # network: 1100::/16, equal # user: unset # role: unset # type: unset # range: unset nodecon 1100:: ffff:: system:system:system:s0:c0.c1 # test 111: # network: 1110:8000::/17, overlap # user: unset # role: unset # type: unset # range: unset nodecon 1110:: ffff:: system:system:system:s0:c0.c1 setools-4.1.1/tests/nodeconquery.py000066400000000000000000000241031314142262400174330ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import sys import unittest from socket import AF_INET6 from setools import SELinuxPolicy, NodeconQuery class NodeconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/nodeconquery.conf") def test_000_unset(self): """Nodecon query with no criteria""" # query with no parameters gets all nodecons. nodecons = sorted(self.p.nodecons()) q = NodeconQuery(self.p) q_nodecons = sorted(q.results()) self.assertListEqual(nodecons, q_nodecons) def test_001_ip_version(self): """Nodecon query with IP version match.""" q = NodeconQuery(self.p, ip_version=AF_INET6) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["1100::", "1110::"], nodecons) def test_020_user_exact(self): """Nodecon query with context user exact match""" q = NodeconQuery(self.p, user="user20", user_regex=False) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.20.1"], nodecons) def test_021_user_regex(self): """Nodecon query with context user regex match""" q = NodeconQuery(self.p, user="user21(a|b)", user_regex=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.21.1", "10.1.21.2"], nodecons) def test_030_role_exact(self): """Nodecon query with context role exact match""" q = NodeconQuery(self.p, role="role30_r", role_regex=False) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.30.1"], nodecons) def test_031_role_regex(self): """Nodecon query with context role regex match""" q = NodeconQuery(self.p, role="role31(a|c)_r", role_regex=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.31.1", "10.1.31.3"], nodecons) def test_040_type_exact(self): """Nodecon query with context type exact match""" q = NodeconQuery(self.p, type_="type40", type_regex=False) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.40.1"], nodecons) def test_041_type_regex(self): """Nodecon query with context type regex match""" q = NodeconQuery(self.p, type_="type41(b|c)", type_regex=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.41.2", "10.1.41.3"], nodecons) def test_050_range_exact(self): """Nodecon query with context range exact match""" q = NodeconQuery(self.p, range_="s0:c1 - s0:c0.c4") nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.50.1"], nodecons) def test_051_range_overlap1(self): """Nodecon query with context range overlap match (equal)""" q = NodeconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.51.1"], nodecons) def test_051_range_overlap2(self): """Nodecon query with context range overlap match (subset)""" q = NodeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.51.1"], nodecons) def test_051_range_overlap3(self): """Nodecon query with context range overlap match (superset)""" q = NodeconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.51.1"], nodecons) def test_051_range_overlap4(self): """Nodecon query with context range overlap match (overlap low level)""" q = NodeconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.51.1"], nodecons) def test_051_range_overlap5(self): """Nodecon query with context range overlap match (overlap high level)""" q = NodeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.51.1"], nodecons) def test_052_range_subset1(self): """Nodecon query with context range subset match""" q = NodeconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.52.1"], nodecons) def test_052_range_subset2(self): """Nodecon query with context range subset match (equal)""" q = NodeconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.52.1"], nodecons) def test_053_range_superset1(self): """Nodecon query with context range superset match""" q = NodeconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.53.1"], nodecons) def test_053_range_superset2(self): """Nodecon query with context range superset match (equal)""" q = NodeconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.53.1"], nodecons) def test_054_range_proper_subset1(self): """Nodecon query with context range proper subset match""" q = NodeconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.54.1"], nodecons) def test_054_range_proper_subset2(self): """Nodecon query with context range proper subset match (equal)""" q = NodeconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual([], nodecons) def test_054_range_proper_subset3(self): """Nodecon query with context range proper subset match (equal low only)""" q = NodeconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.54.1"], nodecons) def test_054_range_proper_subset4(self): """Nodecon query with context range proper subset match (equal high only)""" q = NodeconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.54.1"], nodecons) def test_055_range_proper_superset1(self): """Nodecon query with context range proper superset match""" q = NodeconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.55.1"], nodecons) def test_055_range_proper_superset2(self): """Nodecon query with context range proper superset match (equal)""" q = NodeconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual([], nodecons) def test_055_range_proper_superset3(self): """Nodecon query with context range proper superset match (equal low)""" q = NodeconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.55.1"], nodecons) def test_055_range_proper_superset4(self): """Nodecon query with context range proper superset match (equal high)""" q = NodeconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.55.1"], nodecons) @unittest.skipIf(sys.version_info < (3, 3), "Requires Python 3.3+.") def test_100_v4network_equal(self): """Nodecon query with IPv4 equal network""" q = NodeconQuery(self.p, network="10.1.100.0/24", network_overlap=False) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.100.0"], nodecons) @unittest.skipIf(sys.version_info < (3, 3), "Requires Python 3.3+.") def test_101_v4network_overlap(self): """Nodecon query with IPv4 network overlap""" q = NodeconQuery(self.p, network="10.1.101.128/25", network_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["10.1.101.0"], nodecons) @unittest.skipIf(sys.version_info < (3, 3), "Requires Python 3.3+.") def test_110_v6network_equal(self): """Nodecon query with IPv6 equal network""" q = NodeconQuery(self.p, network="1100::/16", network_overlap=False) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["1100::"], nodecons) @unittest.skipIf(sys.version_info < (3, 3), "Requires Python 3.3+.") def test_111_v6network_overlap(self): """Nodecon query with IPv6 network overlap""" q = NodeconQuery(self.p, network="1110:8000::/17", network_overlap=True) nodecons = sorted(n.address for n in q.results()) self.assertListEqual(["1110::"], nodecons) setools-4.1.1/tests/objclassquery.conf000066400000000000000000000040461314142262400201070ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class infoflow8 class infoflow9 class infoflow10 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } common com_a { hi_w hi_r super_r super_w } common com_b { send recv } common com_c { getattr setattr read write } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow { super_w super_r super_none super_both super_unmapped } class infoflow5 inherits com_a class infoflow6 inherits com_b class infoflow7 inherits infoflow { unmapped } class infoflow8 { super_w super_r } class infoflow9 inherits com_c class infoflow10 { read write } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/objclassquery.py000066400000000000000000000107301314142262400176070ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, ObjClassQuery class ObjClassQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/objclassquery.conf") def test_000_unset(self): """Class query with no criteria.""" # query with no parameters gets all types. classes = sorted(self.p.classes()) q = ObjClassQuery(self.p) q_classes = sorted(q.results()) self.assertListEqual(classes, q_classes) def test_001_name_exact(self): """Class query with exact name match.""" q = ObjClassQuery(self.p, name="infoflow") classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow"], classes) def test_002_name_regex(self): """Class query with regex name match.""" q = ObjClassQuery(self.p, name="infoflow(2|3)", name_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow3"], classes) def test_010_common_exact(self): """Class query with exact common name match.""" q = ObjClassQuery(self.p, common="infoflow") classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow", "infoflow2", "infoflow4", "infoflow7"], classes) def test_011_common_regex(self): """Class query with regex common name match.""" q = ObjClassQuery(self.p, common="com_[ab]", common_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow5", "infoflow6"], classes) def test_020_perm_indirect_intersect(self): """Class query with indirect, intersect permission name patch.""" q = ObjClassQuery( self.p, perms=set(["send"]), perms_indirect=True, perms_equal=False) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow6"], classes) def test_021_perm_direct_intersect(self): """Class query with direct, intersect permission name patch.""" q = ObjClassQuery( self.p, perms=set(["super_r"]), perms_indirect=False, perms_equal=False) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow4", "infoflow8"], classes) def test_022_perm_indirect_equal(self): """Class query with indirect, equal permission name patch.""" q = ObjClassQuery(self.p, perms=set( ["low_w", "med_w", "hi_w", "low_r", "med_r", "hi_r", "unmapped"]), perms_indirect=True, perms_equal=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow7"], classes) def test_023_perm_direct_equal(self): """Class query with direct, equal permission name patch.""" q = ObjClassQuery(self.p, perms=set( ["super_r", "super_w"]), perms_indirect=False, perms_equal=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow8"], classes) def test_024_perm_indirect_regex(self): """Class query with indirect, regex permission name patch.""" q = ObjClassQuery( self.p, perms="(send|setattr)", perms_indirect=True, perms_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow6", "infoflow9"], classes) def test_025_perm_direct_regex(self): """Class query with direct, regex permission name patch.""" q = ObjClassQuery( self.p, perms="(read|super_r)", perms_indirect=False, perms_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow10", "infoflow2", "infoflow4", "infoflow8"], classes) setools-4.1.1/tests/pcideviceconquery.conf000066400000000000000000000076341314142262400207500ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # pci device: unset # user: unset # role: unset # type: unset # range: unset pcidevicecon 1 system:system:system:s0:c0.c1 # test 10: # pci device: unset # user: user10, exact # role: unset # type: unset # range: unset pcidevicecon 10 user10:system:system:s0:c0.c1 # test 11: # pci device: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset pcidevicecon 11 user11a:system:system:s0:c0.c1 pcidevicecon 11000 user11b:system:system:s0:c0.c1 pcidevicecon 11001 user11c:system:system:s0:c0.c1 # test 20: # pci device: unset # user: unset # role: role20_r, exact # type: unset # range: unset pcidevicecon 20 system:role20_r:system:s0:c0.c1 # test 21: # pci device: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset pcidevicecon 21 system:role21a_r:system:s0:c0.c1 pcidevicecon 21000 system:role21b_r:system:s0:c0.c1 pcidevicecon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # pci device: unset # user: unset # role: unset # type: type30 # range: unset pcidevicecon 30 system:system:type30:s0:c0.c1 # test 31: # pci device: unset # user: unset # role: unset # type: type31(b|c) # range: unset pcidevicecon 31 system:system:type31a:s0:c0.c1 pcidevicecon 31000 system:system:type31b:s0:c0.c1 pcidevicecon 31001 system:system:type31c:s0:c0.c1 # test 40: # pci device: unset # user: unset # role: unset # type: unset # range: equal pcidevicecon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # pci device: unset # user: unset # role: unset # type: unset # range: overlap pcidevicecon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # pci device: unset # user: unset # role: unset # type: unset # range: subset pcidevicecon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # pci device: unset # user: unset # role: unset # type: unset # range: superset pcidevicecon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # pci device: unset # user: unset # role: unset # type: unset # range: proper subset pcidevicecon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # pci device: unset # user: unset # role: unset # type: unset # range: proper superset pcidevicecon 45 system:system:system:s5:c1 - s5:c1.c3 setools-4.1.1/tests/pcideviceconquery.py000066400000000000000000000210561314142262400204450ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, PcideviceconQuery class PcideviceconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/pcideviceconquery.conf") def test_000_unset(self): """Pcidevicecon query with no criteria""" # query with no parameters gets all PCI devices. rules = sorted(self.p.pcidevicecons()) q = PcideviceconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Pcidevicecon query with context user exact match""" q = PcideviceconQuery(self.p, user="user10", user_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(10)], device) def test_011_user_regex(self): """Pcidevicecon query with context user regex match""" q = PcideviceconQuery(self.p, user="user11(a|b)", user_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(11), (11000)], device) def test_020_role_exact(self): """Pcidevicecon query with context role exact match""" q = PcideviceconQuery(self.p, role="role20_r", role_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(20)], device) def test_021_role_regex(self): """Pcidevicecon query with context role regex match""" q = PcideviceconQuery(self.p, role="role21(a|c)_r", role_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(21), (21001)], device) def test_030_type_exact(self): """Pcidevicecon query with context type exact match""" q = PcideviceconQuery(self.p, type_="type30", type_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(30)], device) def test_031_type_regex(self): """Pcidevicecon query with context type regex match""" q = PcideviceconQuery(self.p, type_="type31(b|c)", type_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(31000), (31001)], device) def test_040_range_exact(self): """Pcidevicecon query with context range exact match""" q = PcideviceconQuery(self.p, range_="s0:c1 - s0:c0.c4") device = sorted(p.device for p in q.results()) self.assertListEqual([(40)], device) def test_041_range_overlap1(self): """Pcidevicecon query with context range overlap match (equal)""" q = PcideviceconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap2(self): """Pcidevicecon query with context range overlap match (subset)""" q = PcideviceconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap3(self): """Pcidevicecon query with context range overlap match (superset)""" q = PcideviceconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap4(self): """Pcidevicecon query with context range overlap match (overlap low level)""" q = PcideviceconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap5(self): """Pcidevicecon query with context range overlap match (overlap high level)""" q = PcideviceconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_042_range_subset1(self): """Pcidevicecon query with context range subset match""" q = PcideviceconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(42)], device) def test_042_range_subset2(self): """Pcidevicecon query with context range subset match (equal)""" q = PcideviceconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(42)], device) def test_043_range_superset1(self): """Pcidevicecon query with context range superset match""" q = PcideviceconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(43)], device) def test_043_range_superset2(self): """Pcidevicecon query with context range superset match (equal)""" q = PcideviceconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(43)], device) def test_044_range_proper_subset1(self): """Pcidevicecon query with context range proper subset match""" q = PcideviceconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_044_range_proper_subset2(self): """Pcidevicecon query with context range proper subset match (equal)""" q = PcideviceconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([], device) def test_044_range_proper_subset3(self): """Pcidevicecon query with context range proper subset match (equal low only)""" q = PcideviceconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_044_range_proper_subset4(self): """Pcidevicecon query with context range proper subset match (equal high only)""" q = PcideviceconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_045_range_proper_superset1(self): """Pcidevicecon query with context range proper superset match""" q = PcideviceconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) def test_045_range_proper_superset2(self): """Pcidevicecon query with context range proper superset match (equal)""" q = PcideviceconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([], device) def test_045_range_proper_superset3(self): """Pcidevicecon query with context range proper superset match (equal low)""" q = PcideviceconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) def test_045_range_proper_superset4(self): """Pcidevicecon query with context range proper superset match (equal high)""" q = PcideviceconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) setools-4.1.1/tests/perm_map000066400000000000000000000010051314142262400160650ustar00rootroot00000000000000# this is an early comment 5 # this is a comment before a class class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 # this a comment between classes class infoflow2 7 # this is a comment before perms low_w w 1 med_w w 5 hi_w w 10 # this is a comment between perms low_r r 1 # this is a comment after a perm med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 # this is an extra comment at the end setools-4.1.1/tests/permmap.conf000066400000000000000000000067411314142262400166660ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class file class process class new_class sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super new_perm } class infoflow3 { null } class new_class { new_class_perm } class file { execute entrypoint } class process { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Note: these tests should be to determine if the graph # is being constructed correctly. It is assumed that the # graph algorithms being used are correct, as they are # unit tested by the NetworkX project itself. # # # Max steps for all flows: 6 # # Graph if min weight is 8 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ # 1 -> 2-/ # # 3 5 -> 8 <-> 9 # # Graph if min weight is 3 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 5 -> 8 <-> 9 # # Graph if min weight is 1 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 -> 5 -> 8 <-> 9 # # # attribute allnodes; type node1, allnodes; type node2, allnodes; type node3, allnodes; type node4, allnodes; type node5, allnodes; type node6, allnodes; type node7, allnodes; type node8, allnodes; type node9, allnodes; # no infoflow allow allnodes allnodes:infoflow3 null; # 1->2 (10, 5) allow node1 node2:infoflow med_w; allow node2 node1:infoflow hi_r; # 1->3 (5, 1) allow node3 node1:infoflow { low_r med_r }; # 2->4 (10) allow node2 node4:infoflow hi_w; # 3->5 (1) allow node5 node3:infoflow low_r; # 4->6 (10) allow node4 node6:infoflow2 hi_w; # 6->5 (5) allow node5 node6:infoflow med_r; # 6->7 (10) allow node6 node7:infoflow hi_w; # 5->8 (10) allow node5 node8:infoflow2 hi_w; # 8 <-> 9 (10) allow node8 node9:infoflow2 super; # disconnected from the main graph # for testing the handling of no # paths. type disconnected1; type disconnected2; allow disconnected1 disconnected2:infoflow2 super; # not an infoflow: type disconnected3; auditallow node1 disconnected3:infoflow hi_w; # infoflow loop that should be ignored: allow disconnected3 self:infoflow hi_w; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/permmap.py000066400000000000000000000405751314142262400163740ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock except ImportError: from mock import Mock from setools import SELinuxPolicy, PermissionMap, TERuletype from setools.exception import PermissionMapParseError, RuleTypeError, \ UnmappedClass, UnmappedPermission class PermissionMapTest(unittest.TestCase): """Permission map unit tests.""" def validate_permmap_entry(self, permmap, cls, perm, direction, weight, enabled): """Validate a permission map entry and settings.""" self.assertIn(cls, permmap) self.assertIn(perm, permmap[cls]) self.assertIn('direction', permmap[cls][perm]) self.assertIn('weight', permmap[cls][perm]) self.assertIn('enabled', permmap[cls][perm]) self.assertEqual(permmap[cls][perm]['direction'], direction) self.assertEqual(permmap[cls][perm]['weight'], weight) if enabled: self.assertTrue(permmap[cls][perm]['enabled']) else: self.assertFalse(permmap[cls][perm]['enabled']) def test_001_load(self): """PermMap open from path.""" permmap = PermissionMap("tests/perm_map") # validate permission map contents self.assertEqual(5, len(permmap.permmap)) # class infoflow self.assertIn("infoflow", permmap.permmap) self.assertEqual(6, len(permmap.permmap['infoflow'])) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'low_w', 'w', 1, True) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'med_w', 'w', 5, True) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'hi_w', 'w', 10, True) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'low_r', 'r', 1, True) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'med_r', 'r', 5, True) self.validate_permmap_entry(permmap.permmap, 'infoflow', 'hi_r', 'r', 10, True) # class infoflow2 self.assertIn("infoflow2", permmap.permmap) self.assertEqual(7, len(permmap.permmap['infoflow2'])) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_w', 'w', 1, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'med_w', 'w', 5, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'hi_w', 'w', 10, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_r', 'r', 1, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'med_r', 'r', 5, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'hi_r', 'r', 10, True) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'super', 'b', 10, True) # class infoflow3 self.assertIn("infoflow3", permmap.permmap) self.assertEqual(1, len(permmap.permmap['infoflow3'])) self.validate_permmap_entry(permmap.permmap, 'infoflow3', 'null', 'n', 1, True) # class file self.assertIn("file", permmap.permmap) self.assertEqual(2, len(permmap.permmap['file'])) self.validate_permmap_entry(permmap.permmap, 'file', 'execute', 'r', 10, True) self.validate_permmap_entry(permmap.permmap, 'file', 'entrypoint', 'r', 10, True) # class process self.assertIn("process", permmap.permmap) self.assertEqual(1, len(permmap.permmap['process'])) self.validate_permmap_entry(permmap.permmap, 'process', 'transition', 'w', 10, True) def test_002_load_invalid(self): """PermMap load completely wrong file type""" with self.assertRaises(PermissionMapParseError): PermissionMap("setup.py") def test_002_load_negative_class_count(self): """PermMap load negative class count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/negative-classcount") def test_003_load_non_number_class_count(self): """PermMap load non-number class count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/non-number-classcount") def test_004_load_extra_class(self): """PermMap load extra class""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/extra-class") def test_005_load_bad_class_keyword(self): """PermMap load bad class keyword""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-class-keyword") # test 6: bad class name(?) def test_007_load_negative_perm_count(self): """PermMap load negative permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/negative-permcount") def test_008_load_bad_perm_count(self): """PermMap load bad permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-permcount") # test 9: bad perm name(?) def test_010_load_extra_perms(self): """PermMap load negative permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/extra-perms") def test_011_load_invalid_flow_direction(self): """PermMap load invalid flow direction""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/invalid-flowdir") def test_012_load_bad_perm_weight(self): """PermMap load too high/low permission weight""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-perm-weight-high") with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-perm-weight-low") def test_013_load_invalid_weight(self): """PermMap load invalid permission weight""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/invalid-perm-weight") def test_100_set_weight(self): """PermMap set weight""" permmap = PermissionMap("tests/perm_map") self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_w', 'w', 1, True) permmap.set_weight("infoflow2", "low_w", 10) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_w', 'w', 10, True) def test_101_set_weight_low(self): """PermMap set weight low""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 0) with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", -10) def test_102_set_weight_low(self): """PermMap set weight high""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 11) with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 50) def test_103_set_weight_unmapped_class(self): """PermMap set weight unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.set_weight("UNMAPPED", "write", 10) def test_104_set_weight_unmapped_permission(self): """PermMap set weight unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.set_weight("infoflow2", "UNMAPPED", 10) def test_110_set_direction(self): """PermMap set direction""" permmap = PermissionMap("tests/perm_map") self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_w', 'w', 1, True) permmap.set_direction("infoflow2", "low_w", "r") self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'low_w', 'r', 1, True) def test_111_set_direction_invalid(self): """PermMap set invalid direction""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_direction("infoflow2", "low_w", "X") def test_112_set_direction_unmapped_class(self): """PermMap set direction unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.set_direction("UNMAPPED", "write", "w") def test_113_set_direction_unmapped_permission(self): """PermMap set direction unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.set_direction("infoflow2", "UNMAPPED", "w") def test_120_exclude_perm(self): """PermMap exclude permission.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "med_w") self.validate_permmap_entry(permmap.permmap, 'infoflow', 'med_w', 'w', 5, False) def test_121_exclude_perm_unmapped_class(self): """PermMap exclude permission unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.exclude_permission("UNMAPPED", "med_w") def test_122_exclude_perm_unmapped_perm(self): """PermMap exclude permission unmapped permission.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.exclude_permission("infoflow", "UNMAPPED") def test_123_include_perm(self): """PermMap include permission.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "med_w") self.validate_permmap_entry(permmap.permmap, 'infoflow', 'med_w', 'w', 5, False) permmap.include_permission("infoflow", "med_w") self.validate_permmap_entry(permmap.permmap, 'infoflow', 'med_w', 'w', 5, True) def test_124_include_perm_unmapped_class(self): """PermMap include permission unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.include_permission("UNMAPPED", "med_w") def test_125_include_perm_unmapped_perm(self): """PermMap include permission unmapped permission.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.include_permission("infoflow", "UNMAPPED") def test_130_exclude_class(self): """PermMap exclude class.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_class("file") self.validate_permmap_entry(permmap.permmap, 'file', 'execute', 'r', 10, False) self.validate_permmap_entry(permmap.permmap, 'file', 'entrypoint', 'r', 10, False) def test_131_exclude_class_unmapped_class(self): """PermMap exclude class unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.exclude_class("UNMAPPED") def test_132_include_class(self): """PermMap exclude class.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_class("file") self.validate_permmap_entry(permmap.permmap, 'file', 'execute', 'r', 10, False) self.validate_permmap_entry(permmap.permmap, 'file', 'entrypoint', 'r', 10, False) permmap.include_class("file") self.validate_permmap_entry(permmap.permmap, 'file', 'execute', 'r', 10, True) self.validate_permmap_entry(permmap.permmap, 'file', 'entrypoint', 'r', 10, True) def test_133_include_class_unmapped_class(self): """PermMap include class unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.include_class("UNMAPPED") def test_140_weight_read_only(self): """PermMap get weight of read-only rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["med_r", "hi_r"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 10) self.assertEqual(w, 0) def test_141_weight_write_only(self): """PermMap get weight of write-only rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_w", "med_w"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 5) def test_142_weight_both(self): """PermMap get weight of both rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "hi_w"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 1) self.assertEqual(w, 10) def test_143_weight_none(self): """PermMap get weight of none rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow3" rule.perms = set(["null"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 0) def test_144_weight_unmapped_class(self): """PermMap get weight of rule with unmapped class.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "unmapped" rule.perms = set(["null"]) permmap = PermissionMap("tests/perm_map") self.assertRaises(UnmappedClass, permmap.rule_weight, rule) def test_145_weight_unmapped_permission(self): """PermMap get weight of rule with unmapped permission.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "unmapped"]) permmap = PermissionMap("tests/perm_map") self.assertRaises(UnmappedPermission, permmap.rule_weight, rule) def test_146_weight_wrong_rule_type(self): """PermMap get weight of rule with wrong rule type.""" rule = Mock() rule.ruletype = TERuletype.type_transition rule.tclass = "infoflow" permmap = PermissionMap("tests/perm_map") self.assertRaises(RuleTypeError, permmap.rule_weight, rule) def test_147_weight_excluded_permission(self): """PermMap get weight of a rule with excluded permission.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["med_r", "hi_r"]) permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "hi_r") r, w = permmap.rule_weight(rule) self.assertEqual(r, 5) self.assertEqual(w, 0) def test_148_weight_excluded_class(self): """PermMap get weight of a rule with excluded class.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "med_r", "hi_r", "low_w", "med_w", "hi_w"]) permmap = PermissionMap("tests/perm_map") permmap.exclude_class("infoflow") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 0) def test_150_map_policy(self): """PermMap create mappings for classes/perms in a policy.""" policy = SELinuxPolicy("tests/permmap.conf") permmap = PermissionMap("tests/perm_map") permmap.map_policy(policy) self.validate_permmap_entry(permmap.permmap, 'infoflow2', 'new_perm', 'u', 1, True) self.assertIn("new_class", permmap.permmap) self.assertEqual(1, len(permmap.permmap['new_class'])) self.validate_permmap_entry(permmap.permmap, 'new_class', 'new_class_perm', 'u', 1, True) setools-4.1.1/tests/pirqconquery.conf000066400000000000000000000073421314142262400177640ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # irq: unset # user: unset # role: unset # type: unset # range: unset pirqcon 1 system:system:system:s0:c0.c1 # test 10: # irq: unset # user: user10, exact # role: unset # type: unset # range: unset pirqcon 10 user10:system:system:s0:c0.c1 # test 11: # irq: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset pirqcon 11 user11a:system:system:s0:c0.c1 pirqcon 11000 user11b:system:system:s0:c0.c1 pirqcon 11001 user11c:system:system:s0:c0.c1 # test 20: # irq: unset # user: unset # role: role20_r, exact # type: unset # range: unset pirqcon 20 system:role20_r:system:s0:c0.c1 # test 21: # irq: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset pirqcon 21 system:role21a_r:system:s0:c0.c1 pirqcon 21000 system:role21b_r:system:s0:c0.c1 pirqcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # irq: unset # user: unset # role: unset # type: type30 # range: unset pirqcon 30 system:system:type30:s0:c0.c1 # test 31: # irq: unset # user: unset # role: unset # type: type31(b|c) # range: unset pirqcon 31 system:system:type31a:s0:c0.c1 pirqcon 31000 system:system:type31b:s0:c0.c1 pirqcon 31001 system:system:type31c:s0:c0.c1 # test 40: # irq: unset # user: unset # role: unset # type: unset # range: equal pirqcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # irq: unset # user: unset # role: unset # type: unset # range: overlap pirqcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # irq: unset # user: unset # role: unset # type: unset # range: subset pirqcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # irq: unset # user: unset # role: unset # type: unset # range: superset pirqcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # irq: unset # user: unset # role: unset # type: unset # range: proper subset pirqcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # irq: unset # user: unset # role: unset # type: unset # range: proper superset pirqcon 45 system:system:system:s5:c1 - s5:c1.c3 setools-4.1.1/tests/pirqconquery.py000066400000000000000000000175631314142262400174750ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, PirqconQuery class PirqconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/pirqconquery.conf") def test_000_unset(self): """Pirqcon query with no criteria""" # query with no parameters gets all PCI irqs. rules = sorted(self.p.pirqcons()) q = PirqconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Pirqcon query with context user exact match""" q = PirqconQuery(self.p, user="user10", user_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(10)], irq) def test_011_user_regex(self): """Pirqcon query with context user regex match""" q = PirqconQuery(self.p, user="user11(a|b)", user_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(11), (11000)], irq) def test_020_role_exact(self): """Pirqcon query with context role exact match""" q = PirqconQuery(self.p, role="role20_r", role_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(20)], irq) def test_021_role_regex(self): """Pirqcon query with context role regex match""" q = PirqconQuery(self.p, role="role21(a|c)_r", role_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(21), (21001)], irq) def test_030_type_exact(self): """Pirqcon query with context type exact match""" q = PirqconQuery(self.p, type_="type30", type_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(30)], irq) def test_031_type_regex(self): """Pirqcon query with context type regex match""" q = PirqconQuery(self.p, type_="type31(b|c)", type_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(31000), (31001)], irq) def test_040_range_exact(self): """Pirqcon query with context range exact match""" q = PirqconQuery(self.p, range_="s0:c1 - s0:c0.c4") irq = sorted(p.irq for p in q.results()) self.assertListEqual([(40)], irq) def test_041_range_overlap1(self): """Pirqcon query with context range overlap match (equal)""" q = PirqconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap2(self): """Pirqcon query with context range overlap match (subset)""" q = PirqconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap3(self): """Pirqcon query with context range overlap match (superset)""" q = PirqconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap4(self): """Pirqcon query with context range overlap match (overlap low level)""" q = PirqconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap5(self): """Pirqcon query with context range overlap match (overlap high level)""" q = PirqconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_042_range_subset1(self): """Pirqcon query with context range subset match""" q = PirqconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(42)], irq) def test_042_range_subset2(self): """Pirqcon query with context range subset match (equal)""" q = PirqconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(42)], irq) def test_043_range_superset1(self): """Pirqcon query with context range superset match""" q = PirqconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(43)], irq) def test_043_range_superset2(self): """Pirqcon query with context range superset match (equal)""" q = PirqconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(43)], irq) def test_044_range_proper_subset1(self): """Pirqcon query with context range proper subset match""" q = PirqconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_044_range_proper_subset2(self): """Pirqcon query with context range proper subset match (equal)""" q = PirqconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([], irq) def test_044_range_proper_subset3(self): """Pirqcon query with context range proper subset match (equal low only)""" q = PirqconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_044_range_proper_subset4(self): """Pirqcon query with context range proper subset match (equal high only)""" q = PirqconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_045_range_proper_superset1(self): """Pirqcon query with context range proper superset match""" q = PirqconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) def test_045_range_proper_superset2(self): """Pirqcon query with context range proper superset match (equal)""" q = PirqconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([], irq) def test_045_range_proper_superset3(self): """Pirqcon query with context range proper superset match (equal low)""" q = PirqconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) def test_045_range_proper_superset4(self): """Pirqcon query with context range proper superset match (equal high)""" q = PirqconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) setools-4.1.1/tests/polcapquery.conf000066400000000000000000000044011314142262400175600ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Policy capabilities query # # this is not as good of a test suite since # the capabilities can only have specific names. # test 1 # name: open_perms policycap open_perms; # test 2 # name: pe?er regex # default: unset # note this should get both capabilities. policycap network_peer_controls; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/polcapquery.py000066400000000000000000000033301314142262400172630ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, PolCapQuery class PolCapQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/polcapquery.conf") def test_000_unset(self): """Policy capability query with no criteria""" # query with no parameters gets all capabilities. allcaps = sorted(self.p.polcaps()) q = PolCapQuery(self.p) qcaps = sorted(q.results()) self.assertListEqual(allcaps, qcaps) def test_001_name_exact(self): """Policy capability query with exact match""" q = PolCapQuery(self.p, name="open_perms", name_regex=False) caps = sorted(str(c) for c in q.results()) self.assertListEqual(["open_perms"], caps) def test_002_name_regex(self): """Policy capability query with regex match""" q = PolCapQuery(self.p, name="pe?er", name_regex=True) caps = sorted(str(c) for c in q.results()) self.assertListEqual(["network_peer_controls", "open_perms"], caps) setools-4.1.1/tests/policyrep/000077500000000000000000000000001314142262400163545ustar00rootroot00000000000000setools-4.1.1/tests/policyrep/__init__.py000066400000000000000000000017311314142262400204670ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from . import default from . import initsid from . import mls from . import mlsrule from . import objclass from . import polcap from . import rbacrule from . import role from . import selinuxpolicy from . import symbol from . import terule from . import typeattr from . import user setools-4.1.1/tests/policyrep/default.py000066400000000000000000000203001314142262400203450ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools.policyrep.default import default_factory, validate_ruletype, validate_default_value, \ validate_default_range, DefaultRuletype, DefaultValue, \ DefaultRangeValue from setools.policyrep.exception import InvalidDefaultType, InvalidDefaultValue, \ InvalidDefaultRange, NoDefaults from setools.policyrep.qpol import qpol_default_object_t, qpol_policy_t @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class DefaultTest(unittest.TestCase): @staticmethod def mock_default(objclass=None, user=None, role=None, type_=None, range_=None): d = Mock(qpol_default_object_t) d.object_class.return_value = objclass d.user_default.return_value = user d.role_default.return_value = role d.type_default.return_value = type_ d.range_default.return_value = range_ return d def setUp(self): self.p = Mock(qpol_policy_t) def test_001_factory_user(self): """Default: factory on qpol object with user default.""" q = self.mock_default("test1", "source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test1", d.tclass) self.assertEqual(DefaultValue.source, d.default) def test_002_factory_role(self): """Default: factory on qpol object with role default.""" q = self.mock_default("test2", role="target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test2", d.tclass) self.assertEqual(DefaultValue.target, d.default) def test_003_factory_type(self): """Default: factory on qpol object with type default.""" q = self.mock_default("test3", type_="source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test3", d.tclass) self.assertEqual(DefaultValue.source, d.default) def test_004_factory_range(self): """Default: factory on qpol object with range default.""" q = self.mock_default("test4", range_="target low_high") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test4", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual(DefaultRangeValue.low_high, d.default_range) def test_005_factory_multiple(self): """Default: factory on qpol object with mulitple defaults.""" q = self.mock_default("test5", "source", "target", "source", "target low") defaults = sorted(default_factory(self.p, q)) self.assertEqual(4, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[1] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[2] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[3] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test5", d.tclass) def test_010_user(self): """Default: default_user methods/attributes.""" q = self.mock_default("test10", "target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test10", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual("default_user test10 target;", str(d)) self.assertEqual(str(d), d.statement()) def test_011_role(self): """Default: default_role methods/attributes.""" q = self.mock_default("test11", role="source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test11", d.tclass) self.assertEqual(DefaultValue.source, d.default) self.assertEqual("default_role test11 source;", str(d)) self.assertEqual(str(d), d.statement()) def test_012_type(self): """Default: default_type methods/attributes.""" q = self.mock_default("test12", type_="target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test12", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual("default_type test12 target;", str(d)) self.assertEqual(str(d), d.statement()) def test_013_range(self): """Default: default_range methods/attributes.""" q = self.mock_default("test13", range_="source high") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test13", d.tclass) self.assertEqual(DefaultValue.source, d.default) self.assertEqual(DefaultRangeValue.high, d.default_range) self.assertEqual("default_range test13 source high;", str(d)) self.assertEqual(str(d), d.statement()) @unittest.skip("Default ruletype changed to an enumeration.") def test_020_validate_ruletype(self): """Default: validate rule type.""" for r in ["default_user", "default_role", "default_type", "default_range"]: self.assertEqual(r, validate_ruletype(r)) @unittest.skip("Default ruletype changed to an enumeration.") def test_021_validate_ruletype_invalid(self): """Default: invalid ruletype""" with self.assertRaises(InvalidDefaultType): validate_ruletype("INVALID") @unittest.skip("Default value changed to an enumeration.") def test_030_validate_default(self): """Default: validate default value.""" for d in ["source", "target"]: self.assertEqual(d, validate_default_value(d)) @unittest.skip("Default value changed to an enumeration.") def test_031_validate_default_invalid(self): """Default query: invalid default value""" with self.assertRaises(InvalidDefaultValue): validate_default_value("INVALID") @unittest.skip("Default range value changed to an enumeration.") def test_040_validate_default_range(self): """Default: validate default range.""" for r in ["low", "high", "low_high"]: self.assertEqual(r, validate_default_range(r)) @unittest.skip("Default range value changed to an enumeration.") def test_041_validate_default_range_invalid(self): """Default query: invalid default range""" with self.assertRaises(InvalidDefaultRange): validate_default_range("INVALID") setools-4.1.1/tests/policyrep/initsid.conf000066400000000000000000000044401314142262400206700ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/initsid.py000066400000000000000000000056461314142262400204040ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import InvalidInitialSid from setools.policyrep.initsid import initialsid_factory @patch('setools.policyrep.context.context_factory', lambda x, y: y) class InitialSIDTest(unittest.TestCase): @staticmethod def mock_sid(name): sid = Mock(qpol.qpol_isid_t) sid.name.return_value = name sid.context.return_value = name+"_context" return sid @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/initsid.conf") def test_001_factory(self): """InitialSID: factory on qpol object.""" q = self.mock_sid("test1") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test1", sid.qpol_symbol.name(self.p.policy)) def test_002_factory_object(self): """InitialSID: factory on InitialSID object.""" q = self.mock_sid("test2") sid1 = initialsid_factory(self.p.policy, q) sid2 = initialsid_factory(self.p.policy, sid1) self.assertIs(sid2, sid1) def test_003_factory_lookup(self): """InitialSID: factory lookup.""" sid = initialsid_factory(self.p.policy, "kernel") self.assertEqual("kernel", sid.qpol_symbol.name(self.p.policy)) def test_004_factory_lookup_invalid(self): """InitialSID: factory lookup.""" with self.assertRaises(InvalidInitialSid): initialsid_factory(self.p.policy, "INVALID") def test_010_string(self): """InitialSID: basic string rendering.""" q = self.mock_sid("test10") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test10", str(sid)) def test_020_statement(self): """InitialSID: context.""" q = self.mock_sid("test20") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test20_context", sid.context) def test_030_statement(self): """InitialSID: statement.""" q = self.mock_sid("test30") sid = initialsid_factory(self.p.policy, q) self.assertEqual("sid test30 test30_context", sid.statement()) setools-4.1.1/tests/policyrep/invalid_policies/000077500000000000000000000000001314142262400216715ustar00rootroot00000000000000setools-4.1.1/tests/policyrep/invalid_policies/nodecon-invalid-range.conf000066400000000000000000000044011314142262400267020ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Booleans Query # # test 1 # name: test1 # default: unset bool test1 true; # test 2 # name: test2(a|b) regex # default: unset bool test2a true; bool test2b true; # test 10 # name: unset # default: false; bool test10a false; bool test10b false; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here # this is an invalid context (invalid range) nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:elsewhere setools-4.1.1/tests/policyrep/invalid_policies/user-level-not-in-range.conf000066400000000000000000000122311314142262400271160ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid matched_sid sid removed_sid sid modified_sid common infoflow { low_w med_w hi_w low_r med_r hi_r } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; ################################################################################ # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; # this is an invalid user: default level is not within the range. user modified_change_range roles system level s3:c1 range s3:c1.c3; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid matched_sid system:system:system:s0 sid removed_sid removed_user:system:system:s0 sid modified_sid system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 # removed nodecons nodecon 127.0.0.2 255.255.255.255 removed_user:object_r:system:s0 nodecon ::2 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff removed_user:object_r:system:s0 # modified nodecons nodecon 127.0.0.3 255.255.255.255 modified_change_level:object_r:system:s2:c1 nodecon ::3 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 127.0.0.5 255.255.255.255 system:object_r:system:s0 nodecon ::5 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/mls.conf000066400000000000000000000044401314142262400200200ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/mls.py000066400000000000000000000737621314142262400175400ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock except ImportError: from mock import Mock from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import MLSDisabled, InvalidLevel, InvalidLevelDecl, InvalidRange, \ InvalidSensitivity, InvalidCategory, NoStatement from setools.policyrep.mls import sensitivity_factory, category_factory, level_factory, \ range_factory, level_decl_factory class SensitivityTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_sens_factory(self, sens, aliases=[]): """Factory function for Sensitivity objects, using a mock qpol object.""" mock_sens = Mock(qpol.qpol_level_t) mock_sens.name.return_value = sens mock_sens.isalias.return_value = False mock_sens.value.return_value = int(sens[1:]) mock_sens.alias_iter = lambda x: iter(aliases) return sensitivity_factory(self.p.policy, mock_sens) def test_000_mls_disabled(self): """Sensitivity factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, sensitivity_factory, mock_p, None) def test_001_lookup(self): """Sensitivity factory policy lookup.""" sens = sensitivity_factory(self.p.policy, "s1") self.assertEqual("s1", sens.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Sensitivity factory policy invalid lookup.""" with self.assertRaises(InvalidSensitivity): sensitivity_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Sensitivity factory policy lookup of Sensitivity object.""" sens1 = sensitivity_factory(self.p.policy, "s1") sens2 = sensitivity_factory(self.p.policy, sens1) self.assertIs(sens2, sens1) def test_010_string(self): """Sensitivity basic string rendering.""" sens = self.mock_sens_factory("s0") self.assertEqual("s0", str(sens)) def test_020_statement(self): """Sensitivity basic statement rendering.""" sens = self.mock_sens_factory("s0") self.assertEqual("sensitivity s0;", sens.statement()) def test_021_statement_alias(self): """Sensitivity one alias statement rendering.""" sens = self.mock_sens_factory("s0", ["name1"]) self.assertEqual("sensitivity s0 alias name1;", sens.statement()) def test_022_statement_alias(self): """Sensitivity two alias statement rendering.""" sens = self.mock_sens_factory("s0", ["name1", "name2"]) self.assertEqual("sensitivity s0 alias { name1 name2 };", sens.statement()) def test_030_value(self): """Sensitivity value.""" sens = self.mock_sens_factory("s17") self.assertEqual(17, sens._value) def test_031_equal(self): """Sensitivity equal.""" sens1 = self.mock_sens_factory("s0") sens2 = self.mock_sens_factory("s0") self.assertEqual(sens1, sens2) def test_032_equal_str(self): """Sensitivity equal to string.""" sens = self.mock_sens_factory("s17") self.assertEqual("s17", sens) def test_033_not_equal(self): """Sensitivity not equal.""" sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertNotEqual(sens1, sens2) def test_034_not_equal_str(self): """Sensitivity not equal to string.""" sens = self.mock_sens_factory("s17") self.assertNotEqual("s0", sens) def test_035_lt(self): """Sensitivity less-than.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertTrue(sens1 < sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertFalse(sens1 < sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertFalse(sens1 < sens2) def test_036_le(self): """Sensitivity less-than-or-equal.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertTrue(sens1 <= sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertTrue(sens1 <= sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertFalse(sens1 <= sens2) def test_037_ge(self): """Sensitivity greater-than-or-equal.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertFalse(sens1 >= sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertTrue(sens1 >= sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertTrue(sens1 >= sens2) def test_038_gt(self): """Sensitivity greater-than.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertFalse(sens1 > sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertFalse(sens1 > sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertTrue(sens1 > sens2) class CategoryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_cat_factory(self, cat, aliases=[]): """Factory function for Category objects, using a mock qpol object.""" mock_cat = Mock(qpol.qpol_cat_t) mock_cat.name.return_value = cat mock_cat.isalias.return_value = False mock_cat.value.return_value = int(cat[1:]) mock_cat.alias_iter = lambda x: iter(aliases) return category_factory(self.p.policy, mock_cat) def test_000_mls_disabled(self): """Category factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, category_factory, mock_p, None) def test_001_lookup(self): """Category factory policy lookup.""" cat = category_factory(self.p.policy, "c1") self.assertEqual("c1", cat.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Category factory policy invalid lookup.""" with self.assertRaises(InvalidCategory): category_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Category factory policy lookup of Category object.""" cat1 = category_factory(self.p.policy, "c1") cat2 = category_factory(self.p.policy, cat1) self.assertIs(cat2, cat1) def test_010_statement(self): """Category basic string rendering.""" cat = self.mock_cat_factory("c0") self.assertEqual("c0", str(cat)) def test_020_statement(self): """Category basic statement rendering.""" cat = self.mock_cat_factory("c0") self.assertEqual("category c0;", cat.statement()) def test_021_statement_alias(self): """Category one alias statement rendering.""" cat = self.mock_cat_factory("c0", ["name1"]) self.assertEqual("category c0 alias name1;", cat.statement()) def test_022_statement_alias(self): """Category two alias statement rendering.""" cat = self.mock_cat_factory("c0", ["name1", "name2"]) self.assertEqual("category c0 alias { name1 name2 };", cat.statement()) def test_030_value(self): """Category value.""" cat = self.mock_cat_factory("c17") self.assertEqual(17, cat._value) class LevelDeclTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_decl_factory(self, sens, cats=[]): """Factory function for LevelDecl objects, using a mock qpol object.""" mock_decl = Mock(qpol.qpol_level_t) mock_decl.name.return_value = sens mock_decl.isalias.return_value = False mock_decl.value.return_value = int(sens[1:]) mock_decl.cat_iter = lambda x: iter(cats) return level_decl_factory(self.p.policy, mock_decl) def test_000_mls_disabled(self): """Level declaration factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, level_decl_factory, mock_p, None) def test_001_lookup(self): """Level declaration factory policy lookup.""" decl = level_decl_factory(self.p.policy, "s1") self.assertEqual("s1", decl.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Level declaration factory policy invalid lookup.""" with self.assertRaises(InvalidLevelDecl): level_decl_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Level declaration factory policy lookup of LevelDecl object.""" level1 = level_decl_factory(self.p.policy, "s1") level2 = level_decl_factory(self.p.policy, level1) self.assertIs(level2, level1) def test_010_string(self): """Level declaration basic string rendering.""" decl = self.mock_decl_factory("s0") self.assertEqual("s0", str(decl)) def test_011_string_single_cat(self): """Level declaration string rendering with one category""" decl = self.mock_decl_factory("s0", ["c0"]) self.assertEqual("s0:c0", str(decl)) def test_012_string_multiple_cat(self): """Level declaration string rendering with multiple categories""" decl = self.mock_decl_factory("s0", ["c0", "c3"]) self.assertEqual("s0:c0,c3", str(decl)) def test_013_string_cat_set(self): """Level declaration string rendering with category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual("s0:c0.c3", str(decl)) def test_014_string_complex(self): """Level declaration string rendering with complex category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3", "c5", "c7", "c8", "c9"]) self.assertEqual("s0:c0.c3,c5,c7.c9", str(decl)) def test_020_statement(self): """Level declaration basic statement rendering.""" decl = self.mock_decl_factory("s0") self.assertEqual("level s0;", decl.statement()) def test_021_statement_single_cat(self): """Level declaration statement rendering with one category""" decl = self.mock_decl_factory("s0", ["c0"]) self.assertEqual("level s0:c0;", decl.statement()) def test_022_statement_multiple_cat(self): """Level declaration statement rendering with multiple categories""" decl = self.mock_decl_factory("s0", ["c0", "c3"]) self.assertEqual("level s0:c0,c3;", decl.statement()) def test_012_string_cat_set(self): """Level declaration statement rendering with category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual("level s0:c0.c3;", decl.statement()) def test_013_statement_complex(self): """Level declaration statement rendering with complex category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3", "c5", "c7", "c8", "c9"]) self.assertEqual("level s0:c0.c3,c5,c7.c9;", decl.statement()) def test_030_equal(self): """Level declaration equal.""" decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertEqual(decl1, decl2) def test_031_equal_str(self): """Level declaration equal to string.""" decl = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertEqual("s17:c0.c3", decl) def test_032_not_equal(self): """Level declaration not equal.""" decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23") self.assertNotEqual(decl1, decl2) def test_033_not_equal_str(self): """Level declaration not equal to string.""" decl = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertNotEqual("s0:c0.c2", decl) def test_034_lt(self): """Level declaration less-than.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 < decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertFalse(decl1 < decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 < decl2) def test_035_le(self): """Level declaration less-than-or-equal.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 <= decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertTrue(decl1 <= decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 <= decl2) def test_036_ge(self): """Level declaration greater-than-or-equal.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 >= decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertTrue(decl1 >= decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 >= decl2) def test_037_gt(self): """Level declaration greater-than.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 > decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertFalse(decl1 > decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 > decl2) class LevelTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_level_factory(self, sens, cats=[]): """Factory function Level objects, using a mock qpol object.""" mock_level = Mock(qpol.qpol_mls_level_t) mock_level.sens_name.return_value = sens mock_level.cat_iter = lambda x: iter(cats) return level_factory(self.p.policy, mock_level) def test_000_mls_disabled(self): """Level factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, level_factory, mock_p, None) def test_001_lookup_no_cats(self): """Level lookup with no categories.""" levelobj = level_factory(self.p.policy, "s2") self.assertEqual("s2", levelobj.qpol_symbol.sens_name(self.p.policy)) self.assertEqual(str(levelobj), "s2") def test_002_lookup_cat_range(self): """Level lookup with category range.""" levelobj = level_factory(self.p.policy, "s1:c0.c13") self.assertEqual(str(levelobj), "s1:c0.c13") def test_003_lookup_complex_cats(self): """Level lookup with complex category set.""" levelobj = level_factory(self.p.policy, "s2:c0.c5,c7,c9.c11,c13") self.assertEqual(str(levelobj), "s2:c0.c5,c7,c9.c11,c13") def test_004_lookup_bad1(self): """Level lookup with garbage.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL") def test_005_lookup_bad2(self): """Level lookup with : in garbage.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL:BAD") def test_006_lookup_bad_cat(self): """Level lookup with invalid category.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:FAIL") def test_007_lookup_bad_cat_range(self): """Level lookup with backwards category range.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c4.c0") def test_008_lookup_cat_range_error(self): """Level lookup with category range parse error.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0.c2.c4") def test_009_lookup_cat_not_assoc(self): """Level lookup with category not associated with sensitivity.""" # c4 is not associated with s0. self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0,c4") def test_00a_lookup_object(self): """Level factory policy lookup of Level object.""" level1 = level_factory(self.p.policy, "s0") level2 = level_factory(self.p.policy, level1) self.assertIs(level2, level1) def test_010_equal(self): """Level equal.""" level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual(level1, level2) def test_011_equal_str(self): """Level equal to string.""" level = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) self.assertEqual("s2:c0.c3", level) def test_012_not_equal(self): """Level not equal.""" level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s0") self.assertNotEqual(level1, level2) def test_013_not_equal_str(self): """Level not equal to string.""" level = self.mock_level_factory("s0", ["c0", "c2"]) self.assertNotEqual("s0:c0.c2", level) def test_014_dom(self): """Level dominate (ge).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 >= level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 >= level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 >= level2) def test_015_domby(self): """Level dominate-by (le).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 <= level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 <= level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 <= level2) def test_016_proper_dom(self): """Level proper dominate (gt).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 > level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 > level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 > level2) def test_017_proper_domby(self): """Level proper dominate-by (lt).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 < level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 < level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 < level2) def test_018_incomp(self): """Level incomparable (xor).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertTrue(level1 ^ level2) def test_020_level_statement(self): """Level has no statement.""" level = self.mock_level_factory("s1") with self.assertRaises(NoStatement): level.statement() class RangeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def test_000_mls_disabled(self): """Range factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, range_factory, mock_p, None) def test_001_range_lookup_single_level(self): """Range lookup with single-level range.""" rangeobj = range_factory(self.p.policy, "s0") self.assertEqual(str(rangeobj), "s0") def test_002_range_lookup_single_level_redundant(self): """Range lookup with single-level range (same range listed twice).""" rangeobj = range_factory(self.p.policy, "s1-s1") self.assertEqual(str(rangeobj), "s1") def test_003_range_lookup_simple(self): """Range lookup with simple range.""" rangeobj = range_factory(self.p.policy, "s0-s1:c0.c10") self.assertEqual(str(rangeobj), "s0 - s1:c0.c10") def test_004_range_lookup_no_cats(self): """Range lookup with no categories.""" rangeobj = range_factory(self.p.policy, "s0-s1") self.assertEqual(str(rangeobj), "s0 - s1") def test_005_range_lookup_complex(self): """Range lookup with complex category set.""" rangeobj = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual(str(rangeobj), "s0:c0.c2 - s2:c0.c5,c7,c9.c11,c13") def test_006_range_lookup_non_dom(self): """Range lookup with non-dominating high level.""" self.assertRaises(InvalidRange, range_factory, self.p.policy, "s1-s0") def test_007_range_lookup_invalid_range_low(self): """Range lookup with an invalid range (low).""" # c13 is not associated with s0. self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0:c13-s2:c13") def test_008_range_lookup_invalid_range_high(self): """Range lookup with an invalid range (high).""" # c13 is not associated with s0. self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0-s0:c13") def test_009_lookup_object(self): """Range factory policy lookup of Range object.""" range1 = range_factory(self.p.policy, "s0") range2 = range_factory(self.p.policy, range1) self.assertIs(range2, range1) def test_020_equal(self): """Range equality.""" rangeobj1 = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") rangeobj2 = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual(rangeobj1, rangeobj2) def test_021_equal(self): """Range equal to string.""" rangeobj = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual("s0:c0.c2-s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2- s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2 -s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2 - s2:c0.c5,c7,c9.c11,c13", rangeobj) def test_022_contains(self): """Range contains a level.""" rangeobj = range_factory(self.p.policy, "s0:c1-s2:c0.c10") # too low level1 = level_factory(self.p.policy, "s0") self.assertNotIn(level1, rangeobj) # low level level2 = level_factory(self.p.policy, "s0:c1") self.assertIn(level2, rangeobj) # mid level3 = level_factory(self.p.policy, "s1:c1,c5") self.assertIn(level3, rangeobj) # high level level4 = level_factory(self.p.policy, "s2:c0.c10") self.assertIn(level4, rangeobj) # too high level5 = level_factory(self.p.policy, "s2:c0.c11") self.assertNotIn(level5, rangeobj) def test_030_range_statement(self): """Range has no statement.""" rangeobj = range_factory(self.p.policy, "s0") with self.assertRaises(NoStatement): rangeobj.statement() setools-4.1.1/tests/policyrep/mlsrule.py000066400000000000000000000074631314142262400204230ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import MLSRuletype as MRT from setools.policyrep.qpol import qpol_policy_t, qpol_range_trans_t from setools.policyrep.mlsrule import mls_rule_factory, validate_ruletype from setools.policyrep.exception import InvalidMLSRuleType, RuleNotConditional @patch('setools.policyrep.mls.range_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class MLSRuleTest(unittest.TestCase): def mock_rangetrans_factory(self, source, target, tclass, default): mock_rule = Mock(qpol_range_trans_t) mock_rule.rule_type.return_value = MRT.range_transition mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.range.return_value = default return mls_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RangeTransition factory lookup.""" with self.assertRaises(TypeError): mls_rule_factory(self.p, "INVALID") def test_001_validate_ruletype(self): """RangeTransition valid rule types.""" self.assertEqual(MRT.range_transition, validate_ruletype("range_transition")) @unittest.skip("MLS ruletype changed to an enumeration.") def test_002_validate_ruletype_invalid(self): """RangeTransition valid rule types.""" with self.assertRaises(InvalidMLSRuleType): self.assertTrue(validate_ruletype("type_transition")) def test_010_ruletype(self): """RangeTransition rule type""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") self.assertEqual(MRT.range_transition, rule.ruletype) def test_020_source_type(self): """RangeTransition source type""" rule = self.mock_rangetrans_factory("source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """RangeTransition target type""" rule = self.mock_rangetrans_factory("a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RangeTransition object class""" rule = self.mock_rangetrans_factory("a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_default(self): """RangeTransition default range""" rule = self.mock_rangetrans_factory("a", "b", "c", "default50") self.assertEqual("default50", rule.default) def test_060_conditional(self): """RangeTransition conditional expression""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_100_statement(self): """RangeTransition statement.""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") self.assertEqual("range_transition a b:c d;", rule.statement()) setools-4.1.1/tests/policyrep/objclass.conf000066400000000000000000000040461314142262400210270ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class infoflow8 class infoflow9 class infoflow10 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } common com_a { hi_w hi_r super_r super_w } common com_b { send recv } common com_c { getattr setattr read write } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow { super_w super_r super_none super_both super_unmapped } class infoflow5 inherits com_a class infoflow6 inherits com_b class infoflow7 inherits infoflow { unmapped } class infoflow8 { super_w super_r } class infoflow9 inherits com_c class infoflow10 { read write } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/policyrep/objclass.py000066400000000000000000000147141314142262400205350ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock except ImportError: from mock import Mock from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import InvalidCommon, InvalidClass from setools.policyrep.objclass import common_factory, class_factory class CommonTest(unittest.TestCase): @staticmethod def mock_common(name, perms): policy = Mock(qpol.qpol_policy_t) com = Mock(qpol.qpol_common_t) com.name.return_value = name com.perm_iter = lambda x: iter(perms) return common_factory(policy, com) @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/objclass.conf") def test_001_lookup(self): """Common: factory policy lookup.""" com = common_factory(self.p.policy, "com_a") self.assertEqual("com_a", com.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Common: factory policy invalid lookup.""" with self.assertRaises(InvalidCommon): common_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Common: factory policy lookup of Common object.""" com1 = common_factory(self.p.policy, "com_b") com2 = common_factory(self.p.policy, com1) self.assertIs(com2, com1) def test_010_string(self): """Common: string representation""" com = self.mock_common("test10", ["perm1", "perm2"]) self.assertEqual("test10", str(com)) def test_020_perms(self): """Common: permissions""" com = self.mock_common("test20", ["perm1", "perm2"]) self.assertEqual(set(["perm1", "perm2"]), com.perms) def test_030_statment(self): """Common: statement.""" com = self.mock_common("test30", ["perm1", "perm2"]) self.assertRegexpMatches(com.statement(), "(" "common test30\n{\n\tperm1\n\tperm2\n}" "|" "common test30\n{\n\tperm2\n\tperm1\n}" ")") def test_040_contains(self): """Common: contains""" com = self.mock_common("test40", ["perm1", "perm2"]) self.assertIn("perm1", com) self.assertNotIn("perm3", com) class ObjClassTest(unittest.TestCase): @staticmethod def mock_class(name, perms, com_perms=[]): policy = Mock(qpol.qpol_policy_t) cls = Mock(qpol.qpol_class_t) cls.name.return_value = name cls.perm_iter = lambda x: iter(perms) if com_perms: com = Mock(qpol.qpol_common_t) com.name.return_value = name+"_common" com.perm_iter = lambda x: iter(com_perms) cls.common.return_value = com else: cls.common.side_effect = ValueError return class_factory(policy, cls) @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/objclass.conf") def test_001_lookup(self): """ObjClass: factory policy lookup.""" cls = class_factory(self.p.policy, "infoflow") self.assertEqual("infoflow", cls.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """ObjClass: factory policy invalid lookup.""" with self.assertRaises(InvalidClass): class_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """ObjClass: factory policy lookup of ObjClass object.""" cls1 = class_factory(self.p.policy, "infoflow4") cls2 = class_factory(self.p.policy, cls1) self.assertIs(cls2, cls1) def test_010_string(self): """ObjClass: string representation""" cls = self.mock_class("test10", ["perm1", "perm2"]) self.assertEqual("test10", str(cls)) def test_020_perms(self): """ObjClass: permissions""" cls = self.mock_class("test20", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertEqual(set(["perm1", "perm2"]), cls.perms) def test_030_statment(self): """ObjClass: statement, no common.""" cls = self.mock_class("test30", ["perm1", "perm2"]) self.assertRegexpMatches(cls.statement(), "(" "class test30\n{\n\tperm1\n\tperm2\n}" "|" "class test30\n{\n\tperm2\n\tperm1\n}" ")") def test_031_statment(self): """ObjClass: statement, with common.""" cls = self.mock_class("test31", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertRegexpMatches(cls.statement(), "(" "class test31\ninherits test31_common\n{\n\tperm1\n\tperm2\n}" "|" "class test31\ninherits test31_common\n{\n\tperm2\n\tperm1\n}" ")") def test_032_statment(self): """ObjClass: statement, with common, no class perms.""" cls = self.mock_class("test32", [], com_perms=["perm3", "perm4"]) self.assertRegexpMatches(cls.statement(), "(" "class test32\ninherits test32_common" "|" "class test32\ninherits test32_common" ")") def test_040_contains(self): """ObjClass: contains""" cls = self.mock_class("test40", ["perm1", "perm2"]) self.assertIn("perm1", cls) self.assertNotIn("perm3", cls) def test_041_contains_common(self): """ObjClass: contains, with common""" cls = self.mock_class("test41", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertIn("perm1", cls) self.assertIn("perm3", cls) self.assertNotIn("perm5", cls) setools-4.1.1/tests/policyrep/polcap.py000066400000000000000000000041661314142262400202130ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock except ImportError: from mock import Mock from setools.policyrep import qpol from setools.policyrep.polcap import polcap_factory class PolCapTest(unittest.TestCase): @staticmethod def mock_cap(name): cap = Mock(qpol.qpol_polcap_t) cap.name.return_value = name return cap def setUp(self): self.p = Mock(qpol.qpol_policy_t) def test_001_factory(self): """PolCap: factory on qpol object.""" q = self.mock_cap("test1") cap = polcap_factory(self.p, q) self.assertEqual("test1", cap.qpol_symbol.name(self.p)) def test_002_factory_object(self): """PolCap: factory on PolCap object.""" q = self.mock_cap("test2") cap1 = polcap_factory(self.p, q) cap2 = polcap_factory(self.p, cap1) self.assertIs(cap2, cap1) def test_003_factory_lookup(self): """PolCap: factory lookup.""" with self.assertRaises(TypeError): polcap_factory(self.p, "open_perms") def test_010_string(self): """PolCap: basic string rendering.""" q = self.mock_cap("test10") cap = polcap_factory(self.p, q) self.assertEqual("test10", str(cap)) def test_020_statement(self): """PolCap: statement.""" q = self.mock_cap("test20") cap = polcap_factory(self.p, q) self.assertEqual("policycap test20;", cap.statement()) setools-4.1.1/tests/policyrep/rbacrule.py000066400000000000000000000142321314142262400205270ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools.policyrep.qpol import qpol_policy_t, qpol_role_allow_t, qpol_role_trans_t from setools.policyrep.rbacrule import rbac_rule_factory, validate_ruletype, RBACRuletype from setools.policyrep.exception import InvalidRBACRuleType, RuleNotConditional, RuleUseError @patch('setools.policyrep.role.role_factory', lambda x, y: y) class RoleAllowTest(unittest.TestCase): def mock_avrule_factory(self, source, target): mock_rule = Mock(qpol_role_allow_t) mock_rule.rule_type.return_value = RBACRuletype.allow mock_rule.source_role.return_value = source mock_rule.target_role.return_value = target return rbac_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RoleAllow factory lookup.""" with self.assertRaises(TypeError): rbac_rule_factory(self.p, "INVALID") @unittest.skip("RBAC ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """RoleAllow valid rule types.""" # no return value means a return of None self.assertEqual("allow", validate_ruletype("allow")) def test_002_validate_ruletype_invalid(self): """RoleAllow valid rule types.""" with self.assertRaises(InvalidRBACRuleType): self.assertTrue(validate_ruletype("range_transition")) def test_010_ruletype(self): """RoleAllow rule type""" rule = self.mock_avrule_factory("a", "b") self.assertEqual(RBACRuletype.allow, rule.ruletype) def test_020_source_role(self): """RoleAllow source role""" rule = self.mock_avrule_factory("source20", "b") self.assertEqual("source20", rule.source) def test_030_target_role(self): """RoleAllow target role""" rule = self.mock_avrule_factory("a", "target30") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RoleAllow object class""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleUseError): rule.tclass def test_060_conditional(self): """RoleAllow conditional expression""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """RoleAllow default role""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleUseError): rule.default def test_100_statement_one_perm(self): """RoleAllow statement.""" rule = self.mock_avrule_factory("a", "b") self.assertEqual("allow a b;", rule.statement()) @patch('setools.policyrep.role.role_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class RoleTransitionTest(unittest.TestCase): def mock_roletrans_factory(self, source, target, tclass, default): mock_rule = Mock(qpol_role_trans_t) mock_rule.rule_type.return_value = RBACRuletype.role_transition mock_rule.source_role.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.default_role.return_value = default return rbac_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RoleTransition factory lookup.""" with self.assertRaises(TypeError): rbac_rule_factory(self.p, "INVALID") def test_001_validate_ruletype(self): """RoleTransition valid rule types.""" self.assertEqual(RBACRuletype.role_transition, validate_ruletype("role_transition")) def test_002_validate_ruletype_invalid(self): """RoleTransition valid rule types.""" with self.assertRaises(InvalidRBACRuleType): self.assertTrue(validate_ruletype("type_transition")) def test_010_ruletype(self): """RoleTransition rule type""" rule = self.mock_roletrans_factory("a", "b", "c", "d") self.assertEqual(RBACRuletype.role_transition, rule.ruletype) def test_020_source_role(self): """RoleTransition source role""" rule = self.mock_roletrans_factory("source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """RoleTransition target type""" rule = self.mock_roletrans_factory("a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RoleTransition object class""" rule = self.mock_roletrans_factory("a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_default(self): """RoleTransition default role""" rule = self.mock_roletrans_factory("a", "b", "c", "default50") self.assertEqual("default50", rule.default) def test_060_conditional(self): """RoleTransition conditional expression""" rule = self.mock_roletrans_factory("a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_100_statement(self): """RoleTransition statement.""" rule = self.mock_roletrans_factory("a", "b", "c", "d") self.assertEqual("role_transition a b:c d;", rule.statement()) setools-4.1.1/tests/policyrep/role.conf000066400000000000000000000044401314142262400201660ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/role.py000066400000000000000000000066471314142262400177040ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock except ImportError: from mock import Mock from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import InvalidRole from setools.policyrep.role import role_factory class RoleTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/role.conf") def mock_role_factory(self, name, types): """Factory function for Role objects, using a mock qpol object.""" mock_role = Mock(qpol.qpol_role_t) mock_role.name.return_value = name mock_role.type_iter = lambda x: iter(types) return role_factory(self.p.policy, mock_role) def test_001_lookup(self): """Role factory policy lookup.""" role = role_factory(self.p.policy, "role20_r") self.assertEqual("role20_r", role.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Role factory policy invalid lookup.""" with self.assertRaises(InvalidRole): role_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Role factory policy lookup of Role object.""" role1 = role_factory(self.p.policy, "role20_r") role2 = role_factory(self.p.policy, role1) self.assertIs(role2, role1) def test_010_string(self): """Role basic string rendering.""" role = self.mock_role_factory("rolename10", ['type1']) self.assertEqual("rolename10", str(role)) def test_020_statement_type(self): """Role statement, one type.""" role = self.mock_role_factory("rolename20", ['type30']) self.assertEqual("role rolename20 types type30;", role.statement()) def test_021_statement_two_types(self): """Role statement, two types.""" role = self.mock_role_factory("rolename21", ['type31a', 'type31b']) self.assertEqual("role rolename21 types { type31a type31b };", role.statement()) def test_022_statement_decl(self): """Role statement, no types.""" # This is an unlikely corner case, where a role # has been declared but has no types. role = self.mock_role_factory("rolename22", []) self.assertEqual("role rolename22;", role.statement()) def test_030_types(self): """Role types generator.""" role = self.mock_role_factory("rolename", ['type31b', 'type31c']) self.assertEqual(['type31b', 'type31c'], sorted(role.types())) def test_040_expand(self): """Role expansion""" role = self.mock_role_factory("rolename", ['type31a', 'type31b', 'type31c']) expanded = list(role.expand()) self.assertEqual(1, len(expanded)) self.assertIs(role, expanded[0]) setools-4.1.1/tests/policyrep/selinuxpolicy.conf000066400000000000000000004321631314142262400221430ustar00rootroot00000000000000# 7 classes class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 # 11 SIDs sid sid_one sid sid_two sid sid_three sid sid_four sid sid_five sid sid_six sid sid_seven sid sid_eight sid sid_nine sid sid_ten sid sid_eleven # 3 commons common low_c { low_w low_r low_none } common med_c { med_w med_r med_none med_both med_fifth } common hi_c { hi_w hi_r hi_third hi_fourth hi_fifth hi_sixth hi_seventh } # 7 classes # 29 permissions (common perms are only counted once) class infoflow inherits low_c class infoflow2 inherits med_c { super_w super_r } class infoflow3 { null } class infoflow4 inherits hi_c { super_both } class infoflow5 inherits hi_c class infoflow6 { ioctl dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable } class infoflow7 inherits hi_c # 13 sensitivities/levels sensitivity s0 alias sens_alias0; sensitivity s1 alias sens_alias1; sensitivity s2 alias sens_alias2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; sensitivity s7; sensitivity s8; sensitivity s9; sensitivity s10; sensitivity s11; sensitivity s12; dominance { s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 } # 17 categories category c0 alias cat_alias0; category c1 alias cat_alias1; category c2 alias cat_alias2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; # 13 levels level s0:c0.c1; level s1:c0.c3; level s2:c0.c5; level s3:c0.c7; level s4:c0.c10; level s5:c0.c7; level s6:c0.c5; level s7:c0.c5; level s8:c0.c5; level s9:c0.c5; level s10:c0.c5; level s11:c0.c5; level s12:c0.c16; # 23 MLS constraints mlsconstrain infoflow low_w ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow low_r ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow low_none ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow2 med_r ((l1 eq l2) or (t1 == attr1)); mlsconstrain infoflow2 med_w ((h1 dom l2) or (t1 == attr1)); mlsconstrain infoflow2 med_none ((h1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow2 med_both ((h1 domby l2) or (t1 == attr1)); mlsconstrain infoflow2 med_fifth ((h1 eq l2) or (t1 == attr1)); mlsconstrain infoflow2 super_r ((l1 incomp h2) or (t1 == attr1)); mlsconstrain infoflow2 super_w ((l1 eq h2) or (t1 == attr1)); mlsconstrain infoflow4 hi_w ((h1 dom l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_r ((h1 domby l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_third ((h1 eq l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_fourth ((h1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_fifth ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_sixth ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_seventh ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow4 super_both ((l1 eq l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_w ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_r ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_third ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_fifth ((l1 dom h2) or (t1 == attr1)); mlsconstrain infoflow5 hi_sixth ((l1 domby h2) or (t1 == attr1)); # 3 mlsvalidatetrans mlsvalidatetrans { infoflow infoflow2 infoflow3 } ((l1 dom l2) or (t3 == attr1)); # 2 policycaps policycap open_perms; policycap network_peer_controls; attribute attr0; attribute attr1; attribute attr2; attribute attr3; attribute attr4; attribute attr5; attribute attr6; attribute attr7; attribute attr8; attribute attr9; attribute attr10; attribute attr11; attribute attr12; attribute attr13; attribute attr14; attribute attr15; attribute attr16; attribute attr17; attribute attr18; attribute attr19; attribute attr20; attribute attr21; attribute attr22; attribute attr23; attribute attr24; attribute attr25; attribute attr26; attribute attr27; attribute attr28; attribute attr29; attribute attr30; attribute attr31; attribute attr32; attribute attr33; attribute attr34; attribute attr35; attribute attr36; attribute attr37; attribute attr38; attribute attr39; attribute attr40; attribute attr41; attribute attr42; attribute attr43; attribute attr44; attribute attr45; attribute attr46; attribute attr47; attribute attr48; attribute attr49; attribute attr50; attribute attr51; attribute attr52; attribute attr53; attribute attr54; attribute attr55; attribute attr56; attribute attr57; attribute attr58; attribute attr59; attribute attr60; attribute attr61; attribute attr62; attribute attr63; attribute attr64; attribute attr65; attribute attr66; attribute attr67; attribute attr68; attribute attr69; attribute attr70; attribute attr71; attribute attr72; attribute attr73; attribute attr74; attribute attr75; attribute attr76; attribute attr77; attribute attr78; attribute attr79; attribute attr80; attribute attr81; attribute attr82; attribute attr83; attribute attr84; attribute attr85; attribute attr86; attribute attr87; attribute attr88; attribute attr89; attribute attr90; attribute attr91; attribute attr92; attribute attr93; attribute attr94; attribute attr95; attribute attr96; attribute attr97; attribute attr98; attribute attr99; attribute attr100; attribute attr101; attribute attr102; attribute attr103; attribute attr104; attribute attr105; attribute attr106; attribute attr107; attribute attr108; attribute attr109; attribute attr110; attribute attr111; attribute attr112; attribute attr113; attribute attr114; attribute attr115; attribute attr116; attribute attr117; attribute attr118; attribute attr119; attribute attr120; attribute attr121; attribute attr122; attribute attr123; attribute attr124; attribute attr125; attribute attr126; attribute attr127; attribute attr128; attribute attr129; attribute attr130; attribute attr131; attribute attr132; attribute attr133; attribute attr134; attribute attr135; attribute attr136; attribute attr137; attribute attr138; attribute attr139; attribute attr140; attribute attr141; attribute attr142; attribute attr143; attribute attr144; attribute attr145; attribute attr146; attribute attr147; attribute attr148; attribute attr149; attribute attr150; attribute attr151; attribute attr152; attribute attr153; attribute attr154; attribute attr155; attribute attr156; ################################################################################ # Type enforcement declarations and rules # 127 booleans bool bool0 true; bool bool1 true; bool bool2 true; bool bool3 true; bool bool4 true; bool bool5 true; bool bool6 true; bool bool7 true; bool bool8 true; bool bool9 true; bool bool10 true; bool bool11 true; bool bool12 true; bool bool13 true; bool bool14 true; bool bool15 true; bool bool16 true; bool bool17 true; bool bool18 true; bool bool19 true; bool bool20 true; bool bool21 true; bool bool22 true; bool bool23 true; bool bool24 true; bool bool25 true; bool bool26 true; bool bool27 true; bool bool28 true; bool bool29 true; bool bool30 true; bool bool31 true; bool bool32 true; bool bool33 true; bool bool34 true; bool bool35 true; bool bool36 true; bool bool37 true; bool bool38 true; bool bool39 true; bool bool40 true; bool bool41 true; bool bool42 true; bool bool43 true; bool bool44 true; bool bool45 true; bool bool46 true; bool bool47 true; bool bool48 true; bool bool49 true; bool bool50 true; bool bool51 true; bool bool52 true; bool bool53 true; bool bool54 true; bool bool55 true; bool bool56 true; bool bool57 true; bool bool58 true; bool bool59 true; bool bool60 true; bool bool61 true; bool bool62 true; bool bool63 true; bool bool64 true; bool bool65 true; bool bool66 true; bool bool67 true; bool bool68 true; bool bool69 true; bool bool70 true; bool bool71 true; bool bool72 true; bool bool73 true; bool bool74 true; bool bool75 true; bool bool76 true; bool bool77 true; bool bool78 true; bool bool79 true; bool bool80 true; bool bool81 true; bool bool82 true; bool bool83 true; bool bool84 true; bool bool85 true; bool bool86 true; bool bool87 true; bool bool88 true; bool bool89 true; bool bool90 true; bool bool91 true; bool bool92 true; bool bool93 true; bool bool94 true; bool bool95 true; bool bool96 true; bool bool97 true; bool bool98 true; bool bool99 true; bool bool100 true; bool bool101 true; bool bool102 true; bool bool103 true; bool bool104 true; bool bool105 true; bool bool106 true; bool bool107 true; bool bool108 true; bool bool109 true; bool bool110 true; bool bool111 true; bool bool112 true; bool bool113 true; bool bool114 true; bool bool115 true; bool bool116 true; bool bool117 true; bool bool118 true; bool bool119 true; bool bool120 true; bool bool121 true; bool bool122 true; bool bool123 true; bool bool124 true; bool bool125 true; bool bool126 true; # 131 roles # one less is declared here # because object_r is injected # by the compiler. role role0; role role1; role role2; role role3; role role4; role role5; role role6; role role7; role role8; role role9; role role10; role role11; role role12; role role13; role role14; role role15; role role16; role role17; role role18; role role19; role role20; role role21; role role22; role role23; role role24; role role25; role role26; role role27; role role28; role role29; role role30; role role31; role role32; role role33; role role34; role role35; role role36; role role37; role role38; role role39; role role40; role role41; role role42; role role43; role role44; role role45; role role46; role role47; role role48; role role49; role role50; role role51; role role52; role role53; role role54; role role55; role role56; role role57; role role58; role role59; role role60; role role61; role role62; role role63; role role64; role role65; role role66; role role67; role role68; role role69; role role70; role role71; role role72; role role73; role role74; role role75; role role76; role role77; role role78; role role79; role role80; role role81; role role82; role role83; role role84; role role85; role role86; role role87; role role88; role role89; role role90; role role91; role role92; role role93; role role94; role role95; role role96; role role97; role role98; role role99; role role100; role role101; role role102; role role103; role role104; role role105; role role106; role role107; role role108; role role109; role role110; role role111; role role112; role role113; role role114; role role115; role role116; role role117; role role118; role role119; role role120; role role121; role role122; role role123; role role124; role role125; role role126; role role127; role role128; role role129; role role0 types type0; role role1 types type0; role role2 types type0; role role3 types type0; role role4 types type0; role role5 types type0; role role6 types type0; role role7 types type0; role role8 types type0; role role9 types type0; role role10 types type0; role role11 types type0; role role12 types type0; role role13 types type0; role role14 types type0; role role15 types type0; role role16 types type0; role role17 types type0; role role18 types type0; role role19 types type0; role role20 types type0; role role21 types type0; role role22 types type0; role role23 types type0; role role24 types type0; role role25 types type0; role role26 types type0; role role27 types type0; role role28 types type0; role role29 types type0; role role30 types type0; role role31 types type0; role role32 types type0; role role33 types type0; role role34 types type0; role role35 types type0; role role36 types type0; role role37 types type0; role role38 types type0; role role39 types type0; role role40 types type0; role role41 types type0; role role42 types type0; role role43 types type0; role role44 types type0; role role45 types type0; role role46 types type0; role role47 types type0; role role48 types type0; role role49 types type0; role role50 types type0; role role51 types type0; role role52 types type0; role role53 types type0; role role54 types type0; role role55 types type0; role role56 types type0; role role57 types type0; role role58 types type0; role role59 types type0; role role60 types type0; role role61 types type0; role role62 types type0; role role63 types type0; role role64 types type0; role role65 types type0; role role66 types type0; role role67 types type0; role role68 types type0; role role69 types type0; role role70 types type0; role role71 types type0; role role72 types type0; role role73 types type0; role role74 types type0; role role75 types type0; role role76 types type0; role role77 types type0; role role78 types type0; role role79 types type0; role role80 types type0; role role81 types type0; role role82 types type0; role role83 types type0; role role84 types type0; role role85 types type0; role role86 types type0; role role87 types type0; role role88 types type0; role role89 types type0; role role90 types type0; role role91 types type0; role role92 types type0; role role93 types type0; role role94 types type0; role role95 types type0; role role96 types type0; role role97 types type0; role role98 types type0; role role99 types type0; role role100 types type0; role role101 types type0; role role102 types type0; role role103 types type0; role role104 types type0; role role105 types type0; role role106 types type0; role role107 types type0; role role108 types type0; role role109 types type0; role role110 types type0; role role111 types type0; role role112 types type0; role role113 types type0; role role114 types type0; role role115 types type0; role role116 types type0; role role117 types type0; role role118 types type0; role role119 types type0; role role120 types type0; role role121 types type0; role role122 types type0; role role123 types type0; role role124 types type0; role role125 types type0; role role126 types type0; role role127 types type0; role role128 types type0; role role129 types type0; # 137 types type type0 alias type_alias0; type type1 alias type_alias1; type type2 alias type_alias2; type type3; type type4; type type5; type type6; type type7; type type8; type type9; type type10; type type11; type type12; type type13; type type14; type type15; type type16; type type17; type type18; type type19; type type20; type type21; type type22; type type23; type type24; type type25; type type26; type type27; type type28; type type29; type type30; type type31; type type32; type type33; type type34; type type35; type type36; type type37; type type38; type type39; type type40; type type41; type type42; type type43; type type44; type type45; type type46; type type47; type type48; type type49; type type50; type type51; type type52; type type53; type type54; type type55; type type56; type type57; type type58; type type59; type type60; type type61; type type62; type type63; type type64; type type65; type type66; type type67; type type68; type type69; type type70; type type71; type type72; type type73; type type74; type type75; type type76; type type77; type type78; type type79; type type80; type type81; type type82; type type83; type type84; type type85; type type86; type type87; type type88; type type89; type type90; type type91; type type92; type type93; type type94; type type95; type type96; type type97; type type98; type type99; type type100; type type101; type type102; type type103; type type104; type type105; type type106; type type107; type type108; type type109; type type110; type type111; type type112; type type113; type type114; type type115; type type116; type type117; type type118; type type119; type type120; type type121; type type122; type type123; type type124; type type125; type type126; type type127; type type128; type type129; type type130; type type131; type type132; type type133; type type134; type type135; type type136; # 73 permissive types permissive type0; permissive type1; permissive type2; permissive type3; permissive type4; permissive type5; permissive type6; permissive type7; permissive type8; permissive type9; permissive type10; permissive type11; permissive type12; permissive type13; permissive type14; permissive type15; permissive type16; permissive type17; permissive type18; permissive type19; permissive type20; permissive type21; permissive type22; permissive type23; permissive type24; permissive type25; permissive type26; permissive type27; permissive type28; permissive type29; permissive type30; permissive type31; permissive type32; permissive type33; permissive type34; permissive type35; permissive type36; permissive type37; permissive type38; permissive type39; permissive type40; permissive type41; permissive type42; permissive type43; permissive type44; permissive type45; permissive type46; permissive type47; permissive type48; permissive type49; permissive type50; permissive type51; permissive type52; permissive type53; permissive type54; permissive type55; permissive type56; permissive type57; permissive type58; permissive type59; permissive type60; permissive type61; permissive type62; permissive type63; permissive type64; permissive type65; permissive type66; permissive type67; permissive type68; permissive type69; permissive type70; permissive type71; permissive type72; # 83 role allows allow role1 role0; allow role2 role1; allow role3 role2; allow role4 role3; allow role5 role4; allow role6 role5; allow role7 role6; allow role8 role7; allow role9 role8; allow role10 role9; allow role11 role10; allow role12 role11; allow role13 role12; allow role14 role13; allow role15 role14; allow role16 role15; allow role17 role16; allow role18 role17; allow role19 role18; allow role20 role19; allow role21 role20; allow role22 role21; allow role23 role22; allow role24 role23; allow role25 role24; allow role26 role25; allow role27 role26; allow role28 role27; allow role29 role28; allow role30 role29; allow role31 role30; allow role32 role31; allow role33 role32; allow role34 role33; allow role35 role34; allow role36 role35; allow role37 role36; allow role38 role37; allow role39 role38; allow role40 role39; allow role41 role40; allow role42 role41; allow role43 role42; allow role44 role43; allow role45 role44; allow role46 role45; allow role47 role46; allow role48 role47; allow role49 role48; allow role50 role49; allow role51 role50; allow role52 role51; allow role53 role52; allow role54 role53; allow role55 role54; allow role56 role55; allow role57 role56; allow role58 role57; allow role59 role58; allow role60 role59; allow role61 role60; allow role62 role61; allow role63 role62; allow role64 role63; allow role65 role64; allow role66 role65; allow role67 role66; allow role68 role67; allow role69 role68; allow role70 role69; allow role71 role70; allow role72 role71; allow role73 role72; allow role74 role73; allow role75 role74; allow role76 role75; allow role77 role76; allow role78 role77; allow role79 role78; allow role80 role79; allow role81 role80; allow role82 role81; allow role83 role82; # 79 role transitions role_transition role1 type0:infoflow role0; role_transition role2 type0:infoflow role1; role_transition role3 type0:infoflow role2; role_transition role4 type0:infoflow role3; role_transition role5 type0:infoflow role4; role_transition role6 type0:infoflow role5; role_transition role7 type0:infoflow role6; role_transition role8 type0:infoflow role7; role_transition role9 type0:infoflow role8; role_transition role10 type0:infoflow role9; role_transition role11 type0:infoflow role10; role_transition role12 type0:infoflow role11; role_transition role13 type0:infoflow role12; role_transition role14 type0:infoflow role13; role_transition role15 type0:infoflow role14; role_transition role16 type0:infoflow role15; role_transition role17 type0:infoflow role16; role_transition role18 type0:infoflow role17; role_transition role19 type0:infoflow role18; role_transition role20 type0:infoflow role19; role_transition role21 type0:infoflow role20; role_transition role22 type0:infoflow role21; role_transition role23 type0:infoflow role22; role_transition role24 type0:infoflow role23; role_transition role25 type0:infoflow role24; role_transition role26 type0:infoflow role25; role_transition role27 type0:infoflow role26; role_transition role28 type0:infoflow role27; role_transition role29 type0:infoflow role28; role_transition role30 type0:infoflow role29; role_transition role31 type0:infoflow role30; role_transition role32 type0:infoflow role31; role_transition role33 type0:infoflow role32; role_transition role34 type0:infoflow role33; role_transition role35 type0:infoflow role34; role_transition role36 type0:infoflow role35; role_transition role37 type0:infoflow role36; role_transition role38 type0:infoflow role37; role_transition role39 type0:infoflow role38; role_transition role40 type0:infoflow role39; role_transition role41 type0:infoflow role40; role_transition role42 type0:infoflow role41; role_transition role43 type0:infoflow role42; role_transition role44 type0:infoflow role43; role_transition role45 type0:infoflow role44; role_transition role46 type0:infoflow role45; role_transition role47 type0:infoflow role46; role_transition role48 type0:infoflow role47; role_transition role49 type0:infoflow role48; role_transition role50 type0:infoflow role49; role_transition role51 type0:infoflow role50; role_transition role52 type0:infoflow role51; role_transition role53 type0:infoflow role52; role_transition role54 type0:infoflow role53; role_transition role55 type0:infoflow role54; role_transition role56 type0:infoflow role55; role_transition role57 type0:infoflow role56; role_transition role58 type0:infoflow role57; role_transition role59 type0:infoflow role58; role_transition role60 type0:infoflow role59; role_transition role61 type0:infoflow role60; role_transition role62 type0:infoflow role61; role_transition role63 type0:infoflow role62; role_transition role64 type0:infoflow role63; role_transition role65 type0:infoflow role64; role_transition role66 type0:infoflow role65; role_transition role67 type0:infoflow role66; role_transition role68 type0:infoflow role67; role_transition role69 type0:infoflow role68; role_transition role70 type0:infoflow role69; role_transition role71 type0:infoflow role70; role_transition role72 type0:infoflow role71; role_transition role73 type0:infoflow role72; role_transition role74 type0:infoflow role73; role_transition role75 type0:infoflow role74; role_transition role76 type0:infoflow role75; role_transition role77 type0:infoflow role76; role_transition role78 type0:infoflow role77; role_transition role79 type0:infoflow role78; # 113 allow rules if ( bool0 ) { allow type0 type0:infoflow low_none; } if ( bool1 ) { allow type1 type1:infoflow low_none; } if ( bool2 ) { allow type2 type2:infoflow low_none; } if ( bool3 ) { allow type3 type3:infoflow low_none; } if ( bool4 ) { allow type4 type4:infoflow low_none; } if ( bool5 ) { allow type5 type5:infoflow low_none; } if ( bool6 ) { allow type6 type6:infoflow low_none; } if ( bool7 ) { allow type7 type7:infoflow low_none; } if ( bool8 ) { allow type8 type8:infoflow low_none; } if ( bool9 ) { allow type9 type9:infoflow low_none; } if ( bool10 ) { allow type10 type10:infoflow low_none; } if ( bool11 ) { allow type11 type11:infoflow low_none; } if ( bool12 ) { allow type12 type12:infoflow low_none; } if ( bool13 ) { allow type13 type13:infoflow low_none; } if ( bool14 ) { allow type14 type14:infoflow low_none; } if ( bool15 ) { allow type15 type15:infoflow low_none; } if ( bool16 ) { allow type16 type16:infoflow low_none; } if ( bool17 ) { allow type17 type17:infoflow low_none; } if ( bool18 ) { allow type18 type18:infoflow low_none; } if ( bool19 ) { allow type19 type19:infoflow low_none; } if ( bool20 ) { allow type20 type20:infoflow low_none; } if ( bool21 ) { allow type21 type21:infoflow low_none; } if ( bool22 ) { allow type22 type22:infoflow low_none; } if ( bool23 ) { allow type23 type23:infoflow low_none; } if ( bool24 ) { allow type24 type24:infoflow low_none; } if ( bool25 ) { allow type25 type25:infoflow low_none; } if ( bool26 ) { allow type26 type26:infoflow low_none; } if ( bool27 ) { allow type27 type27:infoflow low_none; } if ( bool28 ) { allow type28 type28:infoflow low_none; } if ( bool29 ) { allow type29 type29:infoflow low_none; } if ( bool30 ) { allow type30 type30:infoflow low_none; } if ( bool31 ) { allow type31 type31:infoflow low_none; } if ( bool32 ) { allow type32 type32:infoflow low_none; } if ( bool33 ) { allow type33 type33:infoflow low_none; } if ( bool34 ) { allow type34 type34:infoflow low_none; } if ( bool35 ) { allow type35 type35:infoflow low_none; } if ( bool36 ) { allow type36 type36:infoflow low_none; } if ( bool37 ) { allow type37 type37:infoflow low_none; } if ( bool38 ) { allow type38 type38:infoflow low_none; } if ( bool39 ) { allow type39 type39:infoflow low_none; } if ( bool40 ) { allow type40 type40:infoflow low_none; } if ( bool41 ) { allow type41 type41:infoflow low_none; } if ( bool42 ) { allow type42 type42:infoflow low_none; } if ( bool43 ) { allow type43 type43:infoflow low_none; } if ( bool44 ) { allow type44 type44:infoflow low_none; } if ( bool45 ) { allow type45 type45:infoflow low_none; } if ( bool46 ) { allow type46 type46:infoflow low_none; } if ( bool47 ) { allow type47 type47:infoflow low_none; } if ( bool48 ) { allow type48 type48:infoflow low_none; } if ( bool49 ) { allow type49 type49:infoflow low_none; } if ( bool50 ) { allow type50 type50:infoflow low_none; } if ( bool51 ) { allow type51 type51:infoflow low_none; } if ( bool52 ) { allow type52 type52:infoflow low_none; } if ( bool53 ) { allow type53 type53:infoflow low_none; } if ( bool54 ) { allow type54 type54:infoflow low_none; } if ( bool55 ) { allow type55 type55:infoflow low_none; } if ( bool56 ) { allow type56 type56:infoflow low_none; } if ( bool57 ) { allow type57 type57:infoflow low_none; } if ( bool58 ) { allow type58 type58:infoflow low_none; } if ( bool59 ) { allow type59 type59:infoflow low_none; } if ( bool60 ) { allow type60 type60:infoflow low_none; } if ( bool61 ) { allow type61 type61:infoflow low_none; } if ( bool62 ) { allow type62 type62:infoflow low_none; } if ( bool63 ) { allow type63 type63:infoflow low_none; } if ( bool64 ) { allow type64 type64:infoflow low_none; } if ( bool65 ) { allow type65 type65:infoflow low_none; } if ( bool66 ) { allow type66 type66:infoflow low_none; } allow type67 type67:infoflow low_none; allow type68 type68:infoflow low_none; allow type69 type69:infoflow low_none; allow type70 type70:infoflow low_none; allow type71 type71:infoflow low_none; allow type72 type72:infoflow low_none; allow type73 type73:infoflow low_none; allow type74 type74:infoflow low_none; allow type75 type75:infoflow low_none; allow type76 type76:infoflow low_none; allow type77 type77:infoflow low_none; allow type78 type78:infoflow low_none; allow type79 type79:infoflow low_none; allow type80 type80:infoflow low_none; allow type81 type81:infoflow low_none; allow type82 type82:infoflow low_none; allow type83 type83:infoflow low_none; allow type84 type84:infoflow low_none; allow type85 type85:infoflow low_none; allow type86 type86:infoflow low_none; allow type87 type87:infoflow low_none; allow type88 type88:infoflow low_none; allow type89 type89:infoflow low_none; allow type90 type90:infoflow low_none; allow type91 type91:infoflow low_none; allow type92 type92:infoflow low_none; allow type93 type93:infoflow low_none; allow type94 type94:infoflow low_none; allow type95 type95:infoflow low_none; allow type96 type96:infoflow low_none; allow type97 type97:infoflow low_none; allow type98 type98:infoflow low_none; allow type99 type99:infoflow low_none; allow type100 type100:infoflow low_none; allow type101 type101:infoflow low_none; allow type102 type102:infoflow low_none; allow type103 type103:infoflow low_none; allow type104 type104:infoflow low_none; allow type105 type105:infoflow low_none; allow type106 type106:infoflow low_none; allow type107 type107:infoflow low_none; allow type108 type108:infoflow low_none; allow type109 type109:infoflow low_none; allow type110 type110:infoflow low_none; allow type111 type111:infoflow low_none; allow type112 type112:infoflow low_none; # 109 auditallow rules auditallow type0 type0:infoflow low_w; auditallow type1 type1:infoflow low_w; auditallow type2 type2:infoflow low_w; auditallow type3 type3:infoflow low_w; auditallow type4 type4:infoflow low_w; auditallow type5 type5:infoflow low_w; auditallow type6 type6:infoflow low_w; auditallow type7 type7:infoflow low_w; auditallow type8 type8:infoflow low_w; auditallow type9 type9:infoflow low_w; auditallow type10 type10:infoflow low_w; auditallow type11 type11:infoflow low_w; auditallow type12 type12:infoflow low_w; auditallow type13 type13:infoflow low_w; auditallow type14 type14:infoflow low_w; auditallow type15 type15:infoflow low_w; auditallow type16 type16:infoflow low_w; auditallow type17 type17:infoflow low_w; auditallow type18 type18:infoflow low_w; auditallow type19 type19:infoflow low_w; auditallow type20 type20:infoflow low_w; auditallow type21 type21:infoflow low_w; auditallow type22 type22:infoflow low_w; auditallow type23 type23:infoflow low_w; auditallow type24 type24:infoflow low_w; auditallow type25 type25:infoflow low_w; auditallow type26 type26:infoflow low_w; auditallow type27 type27:infoflow low_w; auditallow type28 type28:infoflow low_w; auditallow type29 type29:infoflow low_w; auditallow type30 type30:infoflow low_w; auditallow type31 type31:infoflow low_w; auditallow type32 type32:infoflow low_w; auditallow type33 type33:infoflow low_w; auditallow type34 type34:infoflow low_w; auditallow type35 type35:infoflow low_w; auditallow type36 type36:infoflow low_w; auditallow type37 type37:infoflow low_w; auditallow type38 type38:infoflow low_w; auditallow type39 type39:infoflow low_w; auditallow type40 type40:infoflow low_w; auditallow type41 type41:infoflow low_w; auditallow type42 type42:infoflow low_w; auditallow type43 type43:infoflow low_w; auditallow type44 type44:infoflow low_w; auditallow type45 type45:infoflow low_w; auditallow type46 type46:infoflow low_w; auditallow type47 type47:infoflow low_w; auditallow type48 type48:infoflow low_w; auditallow type49 type49:infoflow low_w; auditallow type50 type50:infoflow low_w; auditallow type51 type51:infoflow low_w; auditallow type52 type52:infoflow low_w; auditallow type53 type53:infoflow low_w; auditallow type54 type54:infoflow low_w; auditallow type55 type55:infoflow low_w; auditallow type56 type56:infoflow low_w; auditallow type57 type57:infoflow low_w; auditallow type58 type58:infoflow low_w; auditallow type59 type59:infoflow low_w; auditallow type60 type60:infoflow low_w; auditallow type61 type61:infoflow low_w; auditallow type62 type62:infoflow low_w; auditallow type63 type63:infoflow low_w; auditallow type64 type64:infoflow low_w; auditallow type65 type65:infoflow low_w; auditallow type66 type66:infoflow low_w; auditallow type67 type67:infoflow low_w; auditallow type68 type68:infoflow low_w; auditallow type69 type69:infoflow low_w; auditallow type70 type70:infoflow low_w; auditallow type71 type71:infoflow low_w; auditallow type72 type72:infoflow low_w; auditallow type73 type73:infoflow low_w; auditallow type74 type74:infoflow low_w; auditallow type75 type75:infoflow low_w; auditallow type76 type76:infoflow low_w; auditallow type77 type77:infoflow low_w; auditallow type78 type78:infoflow low_w; auditallow type79 type79:infoflow low_w; auditallow type80 type80:infoflow low_w; auditallow type81 type81:infoflow low_w; auditallow type82 type82:infoflow low_w; auditallow type83 type83:infoflow low_w; auditallow type84 type84:infoflow low_w; auditallow type85 type85:infoflow low_w; auditallow type86 type86:infoflow low_w; auditallow type87 type87:infoflow low_w; auditallow type88 type88:infoflow low_w; auditallow type89 type89:infoflow low_w; auditallow type90 type90:infoflow low_w; auditallow type91 type91:infoflow low_w; auditallow type92 type92:infoflow low_w; auditallow type93 type93:infoflow low_w; auditallow type94 type94:infoflow low_w; auditallow type95 type95:infoflow low_w; auditallow type96 type96:infoflow low_w; auditallow type97 type97:infoflow low_w; auditallow type98 type98:infoflow low_w; auditallow type99 type99:infoflow low_w; auditallow type100 type100:infoflow low_w; auditallow type101 type101:infoflow low_w; auditallow type102 type102:infoflow low_w; auditallow type103 type103:infoflow low_w; auditallow type104 type104:infoflow low_w; auditallow type105 type105:infoflow low_w; auditallow type106 type106:infoflow low_w; auditallow type107 type107:infoflow low_w; auditallow type108 type108:infoflow low_w; # 107 dontaudit rules dontaudit type0 type0:infoflow low_r; dontaudit type1 type1:infoflow low_r; dontaudit type2 type2:infoflow low_r; dontaudit type3 type3:infoflow low_r; dontaudit type4 type4:infoflow low_r; dontaudit type5 type5:infoflow low_r; dontaudit type6 type6:infoflow low_r; dontaudit type7 type7:infoflow low_r; dontaudit type8 type8:infoflow low_r; dontaudit type9 type9:infoflow low_r; dontaudit type10 type10:infoflow low_r; dontaudit type11 type11:infoflow low_r; dontaudit type12 type12:infoflow low_r; dontaudit type13 type13:infoflow low_r; dontaudit type14 type14:infoflow low_r; dontaudit type15 type15:infoflow low_r; dontaudit type16 type16:infoflow low_r; dontaudit type17 type17:infoflow low_r; dontaudit type18 type18:infoflow low_r; dontaudit type19 type19:infoflow low_r; dontaudit type20 type20:infoflow low_r; dontaudit type21 type21:infoflow low_r; dontaudit type22 type22:infoflow low_r; dontaudit type23 type23:infoflow low_r; dontaudit type24 type24:infoflow low_r; dontaudit type25 type25:infoflow low_r; dontaudit type26 type26:infoflow low_r; dontaudit type27 type27:infoflow low_r; dontaudit type28 type28:infoflow low_r; dontaudit type29 type29:infoflow low_r; dontaudit type30 type30:infoflow low_r; dontaudit type31 type31:infoflow low_r; dontaudit type32 type32:infoflow low_r; dontaudit type33 type33:infoflow low_r; dontaudit type34 type34:infoflow low_r; dontaudit type35 type35:infoflow low_r; dontaudit type36 type36:infoflow low_r; dontaudit type37 type37:infoflow low_r; dontaudit type38 type38:infoflow low_r; dontaudit type39 type39:infoflow low_r; dontaudit type40 type40:infoflow low_r; dontaudit type41 type41:infoflow low_r; dontaudit type42 type42:infoflow low_r; dontaudit type43 type43:infoflow low_r; dontaudit type44 type44:infoflow low_r; dontaudit type45 type45:infoflow low_r; dontaudit type46 type46:infoflow low_r; dontaudit type47 type47:infoflow low_r; dontaudit type48 type48:infoflow low_r; dontaudit type49 type49:infoflow low_r; dontaudit type50 type50:infoflow low_r; dontaudit type51 type51:infoflow low_r; dontaudit type52 type52:infoflow low_r; dontaudit type53 type53:infoflow low_r; dontaudit type54 type54:infoflow low_r; dontaudit type55 type55:infoflow low_r; dontaudit type56 type56:infoflow low_r; dontaudit type57 type57:infoflow low_r; dontaudit type58 type58:infoflow low_r; dontaudit type59 type59:infoflow low_r; dontaudit type60 type60:infoflow low_r; dontaudit type61 type61:infoflow low_r; dontaudit type62 type62:infoflow low_r; dontaudit type63 type63:infoflow low_r; dontaudit type64 type64:infoflow low_r; dontaudit type65 type65:infoflow low_r; dontaudit type66 type66:infoflow low_r; dontaudit type67 type67:infoflow low_r; dontaudit type68 type68:infoflow low_r; dontaudit type69 type69:infoflow low_r; dontaudit type70 type70:infoflow low_r; dontaudit type71 type71:infoflow low_r; dontaudit type72 type72:infoflow low_r; dontaudit type73 type73:infoflow low_r; dontaudit type74 type74:infoflow low_r; dontaudit type75 type75:infoflow low_r; dontaudit type76 type76:infoflow low_r; dontaudit type77 type77:infoflow low_r; dontaudit type78 type78:infoflow low_r; dontaudit type79 type79:infoflow low_r; dontaudit type80 type80:infoflow low_r; dontaudit type81 type81:infoflow low_r; dontaudit type82 type82:infoflow low_r; dontaudit type83 type83:infoflow low_r; dontaudit type84 type84:infoflow low_r; dontaudit type85 type85:infoflow low_r; dontaudit type86 type86:infoflow low_r; dontaudit type87 type87:infoflow low_r; dontaudit type88 type88:infoflow low_r; dontaudit type89 type89:infoflow low_r; dontaudit type90 type90:infoflow low_r; dontaudit type91 type91:infoflow low_r; dontaudit type92 type92:infoflow low_r; dontaudit type93 type93:infoflow low_r; dontaudit type94 type94:infoflow low_r; dontaudit type95 type95:infoflow low_r; dontaudit type96 type96:infoflow low_r; dontaudit type97 type97:infoflow low_r; dontaudit type98 type98:infoflow low_r; dontaudit type99 type99:infoflow low_r; dontaudit type100 type100:infoflow low_r; dontaudit type101 type101:infoflow low_r; dontaudit type102 type102:infoflow low_r; dontaudit type103 type103:infoflow low_r; dontaudit type104 type104:infoflow low_r; dontaudit type105 type105:infoflow low_r; dontaudit type106 type106:infoflow low_r; # 103 neverallow neverallow type0 type0:infoflow2 super_w; neverallow type1 type1:infoflow2 super_w; neverallow type2 type2:infoflow2 super_w; neverallow type3 type3:infoflow2 super_w; neverallow type4 type4:infoflow2 super_w; neverallow type5 type5:infoflow2 super_w; neverallow type6 type6:infoflow2 super_w; neverallow type7 type7:infoflow2 super_w; neverallow type8 type8:infoflow2 super_w; neverallow type9 type9:infoflow2 super_w; neverallow type10 type10:infoflow2 super_w; neverallow type11 type11:infoflow2 super_w; neverallow type12 type12:infoflow2 super_w; neverallow type13 type13:infoflow2 super_w; neverallow type14 type14:infoflow2 super_w; neverallow type15 type15:infoflow2 super_w; neverallow type16 type16:infoflow2 super_w; neverallow type17 type17:infoflow2 super_w; neverallow type18 type18:infoflow2 super_w; neverallow type19 type19:infoflow2 super_w; neverallow type20 type20:infoflow2 super_w; neverallow type21 type21:infoflow2 super_w; neverallow type22 type22:infoflow2 super_w; neverallow type23 type23:infoflow2 super_w; neverallow type24 type24:infoflow2 super_w; neverallow type25 type25:infoflow2 super_w; neverallow type26 type26:infoflow2 super_w; neverallow type27 type27:infoflow2 super_w; neverallow type28 type28:infoflow2 super_w; neverallow type29 type29:infoflow2 super_w; neverallow type30 type30:infoflow2 super_w; neverallow type31 type31:infoflow2 super_w; neverallow type32 type32:infoflow2 super_w; neverallow type33 type33:infoflow2 super_w; neverallow type34 type34:infoflow2 super_w; neverallow type35 type35:infoflow2 super_w; neverallow type36 type36:infoflow2 super_w; neverallow type37 type37:infoflow2 super_w; neverallow type38 type38:infoflow2 super_w; neverallow type39 type39:infoflow2 super_w; neverallow type40 type40:infoflow2 super_w; neverallow type41 type41:infoflow2 super_w; neverallow type42 type42:infoflow2 super_w; neverallow type43 type43:infoflow2 super_w; neverallow type44 type44:infoflow2 super_w; neverallow type45 type45:infoflow2 super_w; neverallow type46 type46:infoflow2 super_w; neverallow type47 type47:infoflow2 super_w; neverallow type48 type48:infoflow2 super_w; neverallow type49 type49:infoflow2 super_w; neverallow type50 type50:infoflow2 super_w; neverallow type51 type51:infoflow2 super_w; neverallow type52 type52:infoflow2 super_w; neverallow type53 type53:infoflow2 super_w; neverallow type54 type54:infoflow2 super_w; neverallow type55 type55:infoflow2 super_w; neverallow type56 type56:infoflow2 super_w; neverallow type57 type57:infoflow2 super_w; neverallow type58 type58:infoflow2 super_w; neverallow type59 type59:infoflow2 super_w; neverallow type60 type60:infoflow2 super_w; neverallow type61 type61:infoflow2 super_w; neverallow type62 type62:infoflow2 super_w; neverallow type63 type63:infoflow2 super_w; neverallow type64 type64:infoflow2 super_w; neverallow type65 type65:infoflow2 super_w; neverallow type66 type66:infoflow2 super_w; neverallow type67 type67:infoflow2 super_w; neverallow type68 type68:infoflow2 super_w; neverallow type69 type69:infoflow2 super_w; neverallow type70 type70:infoflow2 super_w; neverallow type71 type71:infoflow2 super_w; neverallow type72 type72:infoflow2 super_w; neverallow type73 type73:infoflow2 super_w; neverallow type74 type74:infoflow2 super_w; neverallow type75 type75:infoflow2 super_w; neverallow type76 type76:infoflow2 super_w; neverallow type77 type77:infoflow2 super_w; neverallow type78 type78:infoflow2 super_w; neverallow type79 type79:infoflow2 super_w; neverallow type80 type80:infoflow2 super_w; neverallow type81 type81:infoflow2 super_w; neverallow type82 type82:infoflow2 super_w; neverallow type83 type83:infoflow2 super_w; neverallow type84 type84:infoflow2 super_w; neverallow type85 type85:infoflow2 super_w; neverallow type86 type86:infoflow2 super_w; neverallow type87 type87:infoflow2 super_w; neverallow type88 type88:infoflow2 super_w; neverallow type89 type89:infoflow2 super_w; neverallow type90 type90:infoflow2 super_w; neverallow type91 type91:infoflow2 super_w; neverallow type92 type92:infoflow2 super_w; neverallow type93 type93:infoflow2 super_w; neverallow type94 type94:infoflow2 super_w; neverallow type95 type95:infoflow2 super_w; neverallow type96 type96:infoflow2 super_w; neverallow type97 type97:infoflow2 super_w; neverallow type98 type98:infoflow2 super_w; neverallow type99 type99:infoflow2 super_w; neverallow type100 type100:infoflow2 super_w; neverallow type101 type101:infoflow2 super_w; neverallow type102 type102:infoflow2 super_w; # 97 type_transition rules type_transition type1 type0:infoflow type1; type_transition type2 type1:infoflow type2; type_transition type3 type2:infoflow type3; type_transition type4 type3:infoflow type4; type_transition type5 type4:infoflow type5; type_transition type6 type5:infoflow type6; type_transition type7 type6:infoflow type7; type_transition type8 type7:infoflow type8; type_transition type9 type8:infoflow type9; type_transition type10 type9:infoflow type10; type_transition type11 type10:infoflow type11; type_transition type12 type11:infoflow type12; type_transition type13 type12:infoflow type13; type_transition type14 type13:infoflow type14; type_transition type15 type14:infoflow type15; type_transition type16 type15:infoflow type16; type_transition type17 type16:infoflow type17; type_transition type18 type17:infoflow type18; type_transition type19 type18:infoflow type19; type_transition type20 type19:infoflow type20; type_transition type21 type20:infoflow type21; type_transition type22 type21:infoflow type22; type_transition type23 type22:infoflow type23; type_transition type24 type23:infoflow type24; type_transition type25 type24:infoflow type25; type_transition type26 type25:infoflow type26; type_transition type27 type26:infoflow type27; type_transition type28 type27:infoflow type28; type_transition type29 type28:infoflow type29; type_transition type30 type29:infoflow type30; type_transition type31 type30:infoflow type31; type_transition type32 type31:infoflow type32; type_transition type33 type32:infoflow type33; type_transition type34 type33:infoflow type34; type_transition type35 type34:infoflow type35; type_transition type36 type35:infoflow type36; type_transition type37 type36:infoflow type37; type_transition type38 type37:infoflow type38; type_transition type39 type38:infoflow type39; type_transition type40 type39:infoflow type40; type_transition type41 type40:infoflow type41; type_transition type42 type41:infoflow type42; type_transition type43 type42:infoflow type43; type_transition type44 type43:infoflow type44; type_transition type45 type44:infoflow type45; type_transition type46 type45:infoflow type46; type_transition type47 type46:infoflow type47; type_transition type48 type47:infoflow type48; type_transition type49 type48:infoflow type49; type_transition type50 type49:infoflow type50 "name50"; type_transition type51 type50:infoflow type51 "name51"; type_transition type52 type51:infoflow type52 "name52"; type_transition type53 type52:infoflow type53 "name53"; type_transition type54 type53:infoflow type54 "name54"; type_transition type55 type54:infoflow type55 "name55"; type_transition type56 type55:infoflow type56 "name56"; type_transition type57 type56:infoflow type57 "name57"; type_transition type58 type57:infoflow type58 "name58"; type_transition type59 type58:infoflow type59 "name59"; type_transition type60 type59:infoflow type60 "name60"; type_transition type61 type60:infoflow type61 "name61"; type_transition type62 type61:infoflow type62 "name62"; type_transition type63 type62:infoflow type63 "name63"; type_transition type64 type63:infoflow type64 "name64"; type_transition type65 type64:infoflow type65 "name65"; type_transition type66 type65:infoflow type66 "name66"; type_transition type67 type66:infoflow type67 "name67"; type_transition type68 type67:infoflow type68 "name68"; type_transition type69 type68:infoflow type69 "name69"; type_transition type70 type69:infoflow type70 "name70"; type_transition type71 type70:infoflow type71 "name71"; type_transition type72 type71:infoflow type72 "name72"; type_transition type73 type72:infoflow type73 "name73"; type_transition type74 type73:infoflow type74 "name74"; type_transition type75 type74:infoflow type75 "name75"; type_transition type76 type75:infoflow type76 "name76"; type_transition type77 type76:infoflow type77 "name77"; type_transition type78 type77:infoflow type78 "name78"; type_transition type79 type78:infoflow type79 "name79"; type_transition type80 type79:infoflow type80 "name80"; type_transition type81 type80:infoflow type81 "name81"; type_transition type82 type81:infoflow type82 "name82"; type_transition type83 type82:infoflow type83 "name83"; type_transition type84 type83:infoflow type84 "name84"; type_transition type85 type84:infoflow type85 "name85"; type_transition type86 type85:infoflow type86 "name86"; type_transition type87 type86:infoflow type87 "name87"; type_transition type88 type87:infoflow type88 "name88"; type_transition type89 type88:infoflow type89 "name89"; type_transition type90 type89:infoflow type90 "name90"; type_transition type91 type90:infoflow type91 "name91"; type_transition type92 type91:infoflow type92 "name92"; type_transition type93 type92:infoflow type93 "name93"; type_transition type94 type93:infoflow type94 "name94"; type_transition type95 type94:infoflow type95 "name95"; type_transition type96 type95:infoflow type96 "name96"; type_transition type97 type96:infoflow type97 "name97"; # 89 type_change type_change type1 type0:infoflow type1; type_change type2 type1:infoflow type2; type_change type3 type2:infoflow type3; type_change type4 type3:infoflow type4; type_change type5 type4:infoflow type5; type_change type6 type5:infoflow type6; type_change type7 type6:infoflow type7; type_change type8 type7:infoflow type8; type_change type9 type8:infoflow type9; type_change type10 type9:infoflow type10; type_change type11 type10:infoflow type11; type_change type12 type11:infoflow type12; type_change type13 type12:infoflow type13; type_change type14 type13:infoflow type14; type_change type15 type14:infoflow type15; type_change type16 type15:infoflow type16; type_change type17 type16:infoflow type17; type_change type18 type17:infoflow type18; type_change type19 type18:infoflow type19; type_change type20 type19:infoflow type20; type_change type21 type20:infoflow type21; type_change type22 type21:infoflow type22; type_change type23 type22:infoflow type23; type_change type24 type23:infoflow type24; type_change type25 type24:infoflow type25; type_change type26 type25:infoflow type26; type_change type27 type26:infoflow type27; type_change type28 type27:infoflow type28; type_change type29 type28:infoflow type29; type_change type30 type29:infoflow type30; type_change type31 type30:infoflow type31; type_change type32 type31:infoflow type32; type_change type33 type32:infoflow type33; type_change type34 type33:infoflow type34; type_change type35 type34:infoflow type35; type_change type36 type35:infoflow type36; type_change type37 type36:infoflow type37; type_change type38 type37:infoflow type38; type_change type39 type38:infoflow type39; type_change type40 type39:infoflow type40; type_change type41 type40:infoflow type41; type_change type42 type41:infoflow type42; type_change type43 type42:infoflow type43; type_change type44 type43:infoflow type44; type_change type45 type44:infoflow type45; type_change type46 type45:infoflow type46; type_change type47 type46:infoflow type47; type_change type48 type47:infoflow type48; type_change type49 type48:infoflow type49; type_change type50 type49:infoflow type50; type_change type51 type50:infoflow type51; type_change type52 type51:infoflow type52; type_change type53 type52:infoflow type53; type_change type54 type53:infoflow type54; type_change type55 type54:infoflow type55; type_change type56 type55:infoflow type56; type_change type57 type56:infoflow type57; type_change type58 type57:infoflow type58; type_change type59 type58:infoflow type59; type_change type60 type59:infoflow type60; type_change type61 type60:infoflow type61; type_change type62 type61:infoflow type62; type_change type63 type62:infoflow type63; type_change type64 type63:infoflow type64; type_change type65 type64:infoflow type65; type_change type66 type65:infoflow type66; type_change type67 type66:infoflow type67; type_change type68 type67:infoflow type68; type_change type69 type68:infoflow type69; type_change type70 type69:infoflow type70; type_change type71 type70:infoflow type71; type_change type72 type71:infoflow type72; type_change type73 type72:infoflow type73; type_change type74 type73:infoflow type74; type_change type75 type74:infoflow type75; type_change type76 type75:infoflow type76; type_change type77 type76:infoflow type77; type_change type78 type77:infoflow type78; type_change type79 type78:infoflow type79; type_change type80 type79:infoflow type80; type_change type81 type80:infoflow type81; type_change type82 type81:infoflow type82; type_change type83 type82:infoflow type83; type_change type84 type83:infoflow type84; type_change type85 type84:infoflow type85; type_change type86 type85:infoflow type86; type_change type87 type86:infoflow type87; type_change type88 type87:infoflow type88; type_change type89 type88:infoflow type89; # 61 type_member type_member type1 type0:infoflow type1; type_member type2 type1:infoflow type2; type_member type3 type2:infoflow type3; type_member type4 type3:infoflow type4; type_member type5 type4:infoflow type5; type_member type6 type5:infoflow type6; type_member type7 type6:infoflow type7; type_member type8 type7:infoflow type8; type_member type9 type8:infoflow type9; type_member type10 type9:infoflow type10; type_member type11 type10:infoflow type11; type_member type12 type11:infoflow type12; type_member type13 type12:infoflow type13; type_member type14 type13:infoflow type14; type_member type15 type14:infoflow type15; type_member type16 type15:infoflow type16; type_member type17 type16:infoflow type17; type_member type18 type17:infoflow type18; type_member type19 type18:infoflow type19; type_member type20 type19:infoflow type20; type_member type21 type20:infoflow type21; type_member type22 type21:infoflow type22; type_member type23 type22:infoflow type23; type_member type24 type23:infoflow type24; type_member type25 type24:infoflow type25; type_member type26 type25:infoflow type26; type_member type27 type26:infoflow type27; type_member type28 type27:infoflow type28; type_member type29 type28:infoflow type29; type_member type30 type29:infoflow type30; type_member type31 type30:infoflow type31; type_member type32 type31:infoflow type32; type_member type33 type32:infoflow type33; type_member type34 type33:infoflow type34; type_member type35 type34:infoflow type35; type_member type36 type35:infoflow type36; type_member type37 type36:infoflow type37; type_member type38 type37:infoflow type38; type_member type39 type38:infoflow type39; type_member type40 type39:infoflow type40; type_member type41 type40:infoflow type41; type_member type42 type41:infoflow type42; type_member type43 type42:infoflow type43; type_member type44 type43:infoflow type44; type_member type45 type44:infoflow type45; type_member type46 type45:infoflow type46; type_member type47 type46:infoflow type47; type_member type48 type47:infoflow type48; type_member type49 type48:infoflow type49; type_member type50 type49:infoflow type50; type_member type51 type50:infoflow type51; type_member type52 type51:infoflow type52; type_member type53 type52:infoflow type53; type_member type54 type53:infoflow type54; type_member type55 type54:infoflow type55; type_member type56 type55:infoflow type56; type_member type57 type56:infoflow type57; type_member type58 type57:infoflow type58; type_member type59 type58:infoflow type59; type_member type60 type59:infoflow type60; type_member type61 type60:infoflow type61; # 71 range transitions range_transition type0 type0:infoflow s3; range_transition type1 type1:infoflow s3; range_transition type2 type2:infoflow s3; range_transition type3 type3:infoflow s3; range_transition type4 type4:infoflow s3; range_transition type5 type5:infoflow s3; range_transition type6 type6:infoflow s3; range_transition type7 type7:infoflow s3; range_transition type8 type8:infoflow s3; range_transition type9 type9:infoflow s3; range_transition type10 type10:infoflow s3; range_transition type11 type11:infoflow s3; range_transition type12 type12:infoflow s3; range_transition type13 type13:infoflow s3; range_transition type14 type14:infoflow s3; range_transition type15 type15:infoflow s3; range_transition type16 type16:infoflow s3; range_transition type17 type17:infoflow s3; range_transition type18 type18:infoflow s3; range_transition type19 type19:infoflow s3; range_transition type20 type20:infoflow s3; range_transition type21 type21:infoflow s3; range_transition type22 type22:infoflow s3; range_transition type23 type23:infoflow s3; range_transition type24 type24:infoflow s3; range_transition type25 type25:infoflow s3; range_transition type26 type26:infoflow s3; range_transition type27 type27:infoflow s3; range_transition type28 type28:infoflow s3; range_transition type29 type29:infoflow s3; range_transition type30 type30:infoflow s3; range_transition type31 type31:infoflow s3; range_transition type32 type32:infoflow s3; range_transition type33 type33:infoflow s3; range_transition type34 type34:infoflow s3; range_transition type35 type35:infoflow s3; range_transition type36 type36:infoflow s3; range_transition type37 type37:infoflow s3; range_transition type38 type38:infoflow s3; range_transition type39 type39:infoflow s3; range_transition type40 type40:infoflow s3; range_transition type41 type41:infoflow s3; range_transition type42 type42:infoflow s3; range_transition type43 type43:infoflow s3; range_transition type44 type44:infoflow s3; range_transition type45 type45:infoflow s3; range_transition type46 type46:infoflow s3; range_transition type47 type47:infoflow s3; range_transition type48 type48:infoflow s3; range_transition type49 type49:infoflow s3; range_transition type50 type50:infoflow s3; range_transition type51 type51:infoflow s3; range_transition type52 type52:infoflow s3; range_transition type53 type53:infoflow s3; range_transition type54 type54:infoflow s3; range_transition type55 type55:infoflow s3; range_transition type56 type56:infoflow s3; range_transition type57 type57:infoflow s3; range_transition type58 type58:infoflow s3; range_transition type59 type59:infoflow s3; range_transition type60 type60:infoflow s3; range_transition type61 type61:infoflow s3; range_transition type62 type62:infoflow s3; range_transition type63 type63:infoflow s3; range_transition type64 type64:infoflow s3; range_transition type65 type65:infoflow s3; range_transition type66 type66:infoflow s3; range_transition type67 type67:infoflow s3; range_transition type68 type68:infoflow s3; range_transition type69 type69:infoflow s3; range_transition type70 type70:infoflow s3; # 179 allowxperm rules allowxperm type0 type1:infoflow6 ioctl 0x1234; allowxperm type1 type2:infoflow6 ioctl 0x1234; allowxperm type2 type3:infoflow6 ioctl 0x1234; allowxperm type3 type4:infoflow6 ioctl 0x1234; allowxperm type4 type5:infoflow6 ioctl 0x1234; allowxperm type5 type6:infoflow6 ioctl 0x1234; allowxperm type6 type7:infoflow6 ioctl 0x1234; allowxperm type7 type8:infoflow6 ioctl 0x1234; allowxperm type8 type9:infoflow6 ioctl 0x1234; allowxperm type9 type10:infoflow6 ioctl 0x1234; allowxperm type10 type11:infoflow6 ioctl 0x1234; allowxperm type11 type12:infoflow6 ioctl 0x1234; allowxperm type12 type13:infoflow6 ioctl 0x1234; allowxperm type13 type14:infoflow6 ioctl 0x1234; allowxperm type14 type15:infoflow6 ioctl 0x1234; allowxperm type15 type16:infoflow6 ioctl 0x1234; allowxperm type16 type17:infoflow6 ioctl 0x1234; allowxperm type17 type18:infoflow6 ioctl 0x1234; allowxperm type18 type19:infoflow6 ioctl 0x1234; allowxperm type19 type20:infoflow6 ioctl 0x1234; allowxperm type20 type21:infoflow6 ioctl 0x1234; allowxperm type21 type22:infoflow6 ioctl 0x1234; allowxperm type22 type23:infoflow6 ioctl 0x1234; allowxperm type23 type24:infoflow6 ioctl 0x1234; allowxperm type24 type25:infoflow6 ioctl 0x1234; allowxperm type25 type26:infoflow6 ioctl 0x1234; allowxperm type26 type27:infoflow6 ioctl 0x1234; allowxperm type27 type28:infoflow6 ioctl 0x1234; allowxperm type28 type29:infoflow6 ioctl 0x1234; allowxperm type29 type30:infoflow6 ioctl 0x1234; allowxperm type30 type31:infoflow6 ioctl 0x1234; allowxperm type31 type32:infoflow6 ioctl 0x1234; allowxperm type32 type33:infoflow6 ioctl 0x1234; allowxperm type33 type34:infoflow6 ioctl 0x1234; allowxperm type34 type35:infoflow6 ioctl 0x1234; allowxperm type35 type36:infoflow6 ioctl 0x1234; allowxperm type36 type37:infoflow6 ioctl 0x1234; allowxperm type37 type38:infoflow6 ioctl 0x1234; allowxperm type38 type39:infoflow6 ioctl 0x1234; allowxperm type39 type40:infoflow6 ioctl 0x1234; allowxperm type40 type41:infoflow6 ioctl 0x1234; allowxperm type41 type42:infoflow6 ioctl 0x1234; allowxperm type42 type43:infoflow6 ioctl 0x1234; allowxperm type43 type44:infoflow6 ioctl 0x1234; allowxperm type44 type45:infoflow6 ioctl 0x1234; allowxperm type45 type46:infoflow6 ioctl 0x1234; allowxperm type46 type47:infoflow6 ioctl 0x1234; allowxperm type47 type48:infoflow6 ioctl 0x1234; allowxperm type48 type49:infoflow6 ioctl 0x1234; allowxperm type49 type50:infoflow6 ioctl 0x1234; allowxperm type50 type51:infoflow6 ioctl 0x1234; allowxperm type51 type52:infoflow6 ioctl 0x1234; allowxperm type52 type53:infoflow6 ioctl 0x1234; allowxperm type53 type54:infoflow6 ioctl 0x1234; allowxperm type54 type55:infoflow6 ioctl 0x1234; allowxperm type55 type56:infoflow6 ioctl 0x1234; allowxperm type56 type57:infoflow6 ioctl 0x1234; allowxperm type57 type58:infoflow6 ioctl 0x1234; allowxperm type58 type59:infoflow6 ioctl 0x1234; allowxperm type59 type60:infoflow6 ioctl 0x1234; allowxperm type60 type61:infoflow6 ioctl 0x1234; allowxperm type61 type62:infoflow6 ioctl 0x1234; allowxperm type62 type63:infoflow6 ioctl 0x1234; allowxperm type63 type64:infoflow6 ioctl 0x1234; allowxperm type64 type65:infoflow6 ioctl 0x1234; allowxperm type65 type66:infoflow6 ioctl 0x1234; allowxperm type66 type67:infoflow6 ioctl 0x1234; allowxperm type67 type68:infoflow6 ioctl 0x1234; allowxperm type68 type69:infoflow6 ioctl 0x1234; allowxperm type69 type70:infoflow6 ioctl 0x1234; allowxperm type70 type71:infoflow6 ioctl 0x1234; allowxperm type71 type72:infoflow6 ioctl 0x1234; allowxperm type72 type73:infoflow6 ioctl 0x1234; allowxperm type73 type74:infoflow6 ioctl 0x1234; allowxperm type74 type75:infoflow6 ioctl 0x1234; allowxperm type75 type76:infoflow6 ioctl 0x1234; allowxperm type76 type77:infoflow6 ioctl 0x1234; allowxperm type77 type78:infoflow6 ioctl 0x1234; allowxperm type78 type79:infoflow6 ioctl 0x1234; allowxperm type79 type80:infoflow6 ioctl 0x1234; allowxperm type80 type81:infoflow6 ioctl 0x1234; allowxperm type81 type82:infoflow6 ioctl 0x1234; allowxperm type82 type83:infoflow6 ioctl 0x1234; allowxperm type83 type84:infoflow6 ioctl 0x1234; allowxperm type84 type85:infoflow6 ioctl 0x1234; allowxperm type85 type86:infoflow6 ioctl 0x1234; allowxperm type86 type87:infoflow6 ioctl 0x1234; allowxperm type87 type88:infoflow6 ioctl 0x1234; allowxperm type88 type89:infoflow6 ioctl 0x1234; allowxperm type89 type90:infoflow6 ioctl 0x1234; allowxperm type90 type91:infoflow6 ioctl 0x1234; allowxperm type91 type92:infoflow6 ioctl 0x1234; allowxperm type92 type93:infoflow6 ioctl 0x1234; allowxperm type93 type94:infoflow6 ioctl 0x1234; allowxperm type94 type95:infoflow6 ioctl 0x1234; allowxperm type95 type96:infoflow6 ioctl 0x1234; allowxperm type96 type97:infoflow6 ioctl 0x1234; allowxperm type97 type98:infoflow6 ioctl 0x1234; allowxperm type98 type99:infoflow6 ioctl 0x1234; allowxperm type99 type100:infoflow6 ioctl 0x1234; allowxperm type100 type101:infoflow6 ioctl 0x1234; allowxperm type101 type102:infoflow6 ioctl 0x1234; allowxperm type102 type103:infoflow6 ioctl 0x1234; allowxperm type103 type104:infoflow6 ioctl 0x1234; allowxperm type104 type105:infoflow6 ioctl 0x1234; allowxperm type105 type106:infoflow6 ioctl 0x1234; allowxperm type106 type107:infoflow6 ioctl 0x1234; allowxperm type107 type108:infoflow6 ioctl 0x1234; allowxperm type108 type109:infoflow6 ioctl 0x1234; allowxperm type109 type110:infoflow6 ioctl 0x1234; allowxperm type110 type111:infoflow6 ioctl 0x1234; allowxperm type111 type112:infoflow6 ioctl 0x1234; allowxperm type112 type113:infoflow6 ioctl 0x1234; allowxperm type113 type114:infoflow6 ioctl 0x1234; allowxperm type114 type115:infoflow6 ioctl 0x1234; allowxperm type115 type116:infoflow6 ioctl 0x1234; allowxperm type116 type117:infoflow6 ioctl 0x1234; allowxperm type117 type118:infoflow6 ioctl 0x1234; allowxperm type118 type119:infoflow6 ioctl 0x1234; allowxperm type119 type120:infoflow6 ioctl 0x1234; allowxperm type120 type121:infoflow6 ioctl 0x1234; allowxperm type121 type122:infoflow6 ioctl 0x1234; allowxperm type122 type123:infoflow6 ioctl 0x1234; allowxperm type123 type124:infoflow6 ioctl 0x1234; allowxperm type124 type125:infoflow6 ioctl 0x1234; allowxperm type125 type126:infoflow6 ioctl 0x1234; allowxperm type126 type127:infoflow6 ioctl 0x1234; allowxperm type127 type128:infoflow6 ioctl 0x1234; allowxperm type128 type129:infoflow6 ioctl 0x1234; allowxperm type129 type130:infoflow6 ioctl 0x1234; allowxperm type130 type131:infoflow6 ioctl 0x1234; allowxperm type131 type132:infoflow6 ioctl 0x1234; allowxperm type132 type133:infoflow6 ioctl 0x1234; allowxperm type133 type134:infoflow6 ioctl 0x1234; allowxperm type134 type135:infoflow6 ioctl 0x1234; allowxperm type135 type136:infoflow6 ioctl 0x1234; allowxperm type136 type0:infoflow6 ioctl 0x1234; allowxperm type0 type2:infoflow6 ioctl 0x1234; allowxperm type1 type3:infoflow6 ioctl 0x1234; allowxperm type2 type4:infoflow6 ioctl 0x1234; allowxperm type3 type5:infoflow6 ioctl 0x1234; allowxperm type4 type6:infoflow6 ioctl 0x1234; allowxperm type5 type7:infoflow6 ioctl 0x1234; allowxperm type6 type8:infoflow6 ioctl 0x1234; allowxperm type7 type9:infoflow6 ioctl 0x1234; allowxperm type8 type10:infoflow6 ioctl 0x1234; allowxperm type9 type11:infoflow6 ioctl 0x1234; allowxperm type10 type12:infoflow6 ioctl 0x1234; allowxperm type11 type13:infoflow6 ioctl 0x1234; allowxperm type12 type14:infoflow6 ioctl 0x1234; allowxperm type13 type15:infoflow6 ioctl 0x1234; allowxperm type14 type16:infoflow6 ioctl 0x1234; allowxperm type15 type17:infoflow6 ioctl 0x1234; allowxperm type16 type18:infoflow6 ioctl 0x1234; allowxperm type17 type19:infoflow6 ioctl 0x1234; allowxperm type18 type20:infoflow6 ioctl 0x1234; allowxperm type19 type21:infoflow6 ioctl 0x1234; allowxperm type20 type22:infoflow6 ioctl 0x1234; allowxperm type21 type23:infoflow6 ioctl 0x1234; allowxperm type22 type24:infoflow6 ioctl 0x1234; allowxperm type23 type25:infoflow6 ioctl 0x1234; allowxperm type24 type26:infoflow6 ioctl 0x1234; allowxperm type25 type27:infoflow6 ioctl 0x1234; allowxperm type26 type28:infoflow6 ioctl 0x1234; allowxperm type27 type29:infoflow6 ioctl 0x1234; allowxperm type28 type30:infoflow6 ioctl 0x1234; allowxperm type29 type31:infoflow6 ioctl 0x1234; allowxperm type30 type32:infoflow6 ioctl 0x1234; allowxperm type31 type33:infoflow6 ioctl 0x1234; allowxperm type32 type34:infoflow6 ioctl 0x1234; allowxperm type33 type35:infoflow6 ioctl 0x1234; allowxperm type34 type36:infoflow6 ioctl 0x1234; allowxperm type35 type37:infoflow6 ioctl 0x1234; allowxperm type36 type38:infoflow6 ioctl 0x1234; allowxperm type37 type39:infoflow6 ioctl 0x1234; allowxperm type38 type40:infoflow6 ioctl 0x1234; allowxperm type39 type41:infoflow6 ioctl 0x1234; allowxperm type40 type42:infoflow6 ioctl 0x1234; allowxperm type41 type43:infoflow6 ioctl 0x1234; # 181 auditallowxperm rules auditallowxperm type0 type2:infoflow6 ioctl 0x1234; auditallowxperm type1 type3:infoflow6 ioctl 0x1234; auditallowxperm type2 type4:infoflow6 ioctl 0x1234; auditallowxperm type3 type5:infoflow6 ioctl 0x1234; auditallowxperm type4 type6:infoflow6 ioctl 0x1234; auditallowxperm type5 type7:infoflow6 ioctl 0x1234; auditallowxperm type6 type8:infoflow6 ioctl 0x1234; auditallowxperm type7 type9:infoflow6 ioctl 0x1234; auditallowxperm type8 type10:infoflow6 ioctl 0x1234; auditallowxperm type9 type11:infoflow6 ioctl 0x1234; auditallowxperm type10 type12:infoflow6 ioctl 0x1234; auditallowxperm type11 type13:infoflow6 ioctl 0x1234; auditallowxperm type12 type14:infoflow6 ioctl 0x1234; auditallowxperm type13 type15:infoflow6 ioctl 0x1234; auditallowxperm type14 type16:infoflow6 ioctl 0x1234; auditallowxperm type15 type17:infoflow6 ioctl 0x1234; auditallowxperm type16 type18:infoflow6 ioctl 0x1234; auditallowxperm type17 type19:infoflow6 ioctl 0x1234; auditallowxperm type18 type20:infoflow6 ioctl 0x1234; auditallowxperm type19 type21:infoflow6 ioctl 0x1234; auditallowxperm type20 type22:infoflow6 ioctl 0x1234; auditallowxperm type21 type23:infoflow6 ioctl 0x1234; auditallowxperm type22 type24:infoflow6 ioctl 0x1234; auditallowxperm type23 type25:infoflow6 ioctl 0x1234; auditallowxperm type24 type26:infoflow6 ioctl 0x1234; auditallowxperm type25 type27:infoflow6 ioctl 0x1234; auditallowxperm type26 type28:infoflow6 ioctl 0x1234; auditallowxperm type27 type29:infoflow6 ioctl 0x1234; auditallowxperm type28 type30:infoflow6 ioctl 0x1234; auditallowxperm type29 type31:infoflow6 ioctl 0x1234; auditallowxperm type30 type32:infoflow6 ioctl 0x1234; auditallowxperm type31 type33:infoflow6 ioctl 0x1234; auditallowxperm type32 type34:infoflow6 ioctl 0x1234; auditallowxperm type33 type35:infoflow6 ioctl 0x1234; auditallowxperm type34 type36:infoflow6 ioctl 0x1234; auditallowxperm type35 type37:infoflow6 ioctl 0x1234; auditallowxperm type36 type38:infoflow6 ioctl 0x1234; auditallowxperm type37 type39:infoflow6 ioctl 0x1234; auditallowxperm type38 type40:infoflow6 ioctl 0x1234; auditallowxperm type39 type41:infoflow6 ioctl 0x1234; auditallowxperm type40 type42:infoflow6 ioctl 0x1234; auditallowxperm type41 type43:infoflow6 ioctl 0x1234; auditallowxperm type42 type44:infoflow6 ioctl 0x1234; auditallowxperm type43 type45:infoflow6 ioctl 0x1234; auditallowxperm type44 type46:infoflow6 ioctl 0x1234; auditallowxperm type45 type47:infoflow6 ioctl 0x1234; auditallowxperm type46 type48:infoflow6 ioctl 0x1234; auditallowxperm type47 type49:infoflow6 ioctl 0x1234; auditallowxperm type48 type50:infoflow6 ioctl 0x1234; auditallowxperm type49 type51:infoflow6 ioctl 0x1234; auditallowxperm type50 type52:infoflow6 ioctl 0x1234; auditallowxperm type51 type53:infoflow6 ioctl 0x1234; auditallowxperm type52 type54:infoflow6 ioctl 0x1234; auditallowxperm type53 type55:infoflow6 ioctl 0x1234; auditallowxperm type54 type56:infoflow6 ioctl 0x1234; auditallowxperm type55 type57:infoflow6 ioctl 0x1234; auditallowxperm type56 type58:infoflow6 ioctl 0x1234; auditallowxperm type57 type59:infoflow6 ioctl 0x1234; auditallowxperm type58 type60:infoflow6 ioctl 0x1234; auditallowxperm type59 type61:infoflow6 ioctl 0x1234; auditallowxperm type60 type62:infoflow6 ioctl 0x1234; auditallowxperm type61 type63:infoflow6 ioctl 0x1234; auditallowxperm type62 type64:infoflow6 ioctl 0x1234; auditallowxperm type63 type65:infoflow6 ioctl 0x1234; auditallowxperm type64 type66:infoflow6 ioctl 0x1234; auditallowxperm type65 type67:infoflow6 ioctl 0x1234; auditallowxperm type66 type68:infoflow6 ioctl 0x1234; auditallowxperm type67 type69:infoflow6 ioctl 0x1234; auditallowxperm type68 type70:infoflow6 ioctl 0x1234; auditallowxperm type69 type71:infoflow6 ioctl 0x1234; auditallowxperm type70 type72:infoflow6 ioctl 0x1234; auditallowxperm type71 type73:infoflow6 ioctl 0x1234; auditallowxperm type72 type74:infoflow6 ioctl 0x1234; auditallowxperm type73 type75:infoflow6 ioctl 0x1234; auditallowxperm type74 type76:infoflow6 ioctl 0x1234; auditallowxperm type75 type77:infoflow6 ioctl 0x1234; auditallowxperm type76 type78:infoflow6 ioctl 0x1234; auditallowxperm type77 type79:infoflow6 ioctl 0x1234; auditallowxperm type78 type80:infoflow6 ioctl 0x1234; auditallowxperm type79 type81:infoflow6 ioctl 0x1234; auditallowxperm type80 type82:infoflow6 ioctl 0x1234; auditallowxperm type81 type83:infoflow6 ioctl 0x1234; auditallowxperm type82 type84:infoflow6 ioctl 0x1234; auditallowxperm type83 type85:infoflow6 ioctl 0x1234; auditallowxperm type84 type86:infoflow6 ioctl 0x1234; auditallowxperm type85 type87:infoflow6 ioctl 0x1234; auditallowxperm type86 type88:infoflow6 ioctl 0x1234; auditallowxperm type87 type89:infoflow6 ioctl 0x1234; auditallowxperm type88 type90:infoflow6 ioctl 0x1234; auditallowxperm type89 type91:infoflow6 ioctl 0x1234; auditallowxperm type90 type92:infoflow6 ioctl 0x1234; auditallowxperm type91 type93:infoflow6 ioctl 0x1234; auditallowxperm type92 type94:infoflow6 ioctl 0x1234; auditallowxperm type93 type95:infoflow6 ioctl 0x1234; auditallowxperm type94 type96:infoflow6 ioctl 0x1234; auditallowxperm type95 type97:infoflow6 ioctl 0x1234; auditallowxperm type96 type98:infoflow6 ioctl 0x1234; auditallowxperm type97 type99:infoflow6 ioctl 0x1234; auditallowxperm type98 type100:infoflow6 ioctl 0x1234; auditallowxperm type99 type101:infoflow6 ioctl 0x1234; auditallowxperm type100 type102:infoflow6 ioctl 0x1234; auditallowxperm type101 type103:infoflow6 ioctl 0x1234; auditallowxperm type102 type104:infoflow6 ioctl 0x1234; auditallowxperm type103 type105:infoflow6 ioctl 0x1234; auditallowxperm type104 type106:infoflow6 ioctl 0x1234; auditallowxperm type105 type107:infoflow6 ioctl 0x1234; auditallowxperm type106 type108:infoflow6 ioctl 0x1234; auditallowxperm type107 type109:infoflow6 ioctl 0x1234; auditallowxperm type108 type110:infoflow6 ioctl 0x1234; auditallowxperm type109 type111:infoflow6 ioctl 0x1234; auditallowxperm type110 type112:infoflow6 ioctl 0x1234; auditallowxperm type111 type113:infoflow6 ioctl 0x1234; auditallowxperm type112 type114:infoflow6 ioctl 0x1234; auditallowxperm type113 type115:infoflow6 ioctl 0x1234; auditallowxperm type114 type116:infoflow6 ioctl 0x1234; auditallowxperm type115 type117:infoflow6 ioctl 0x1234; auditallowxperm type116 type118:infoflow6 ioctl 0x1234; auditallowxperm type117 type119:infoflow6 ioctl 0x1234; auditallowxperm type118 type120:infoflow6 ioctl 0x1234; auditallowxperm type119 type121:infoflow6 ioctl 0x1234; auditallowxperm type120 type122:infoflow6 ioctl 0x1234; auditallowxperm type121 type123:infoflow6 ioctl 0x1234; auditallowxperm type122 type124:infoflow6 ioctl 0x1234; auditallowxperm type123 type125:infoflow6 ioctl 0x1234; auditallowxperm type124 type126:infoflow6 ioctl 0x1234; auditallowxperm type125 type127:infoflow6 ioctl 0x1234; auditallowxperm type126 type128:infoflow6 ioctl 0x1234; auditallowxperm type127 type129:infoflow6 ioctl 0x1234; auditallowxperm type128 type130:infoflow6 ioctl 0x1234; auditallowxperm type129 type131:infoflow6 ioctl 0x1234; auditallowxperm type130 type132:infoflow6 ioctl 0x1234; auditallowxperm type131 type133:infoflow6 ioctl 0x1234; auditallowxperm type132 type134:infoflow6 ioctl 0x1234; auditallowxperm type133 type135:infoflow6 ioctl 0x1234; auditallowxperm type134 type136:infoflow6 ioctl 0x1234; auditallowxperm type135 type0:infoflow6 ioctl 0x1234; auditallowxperm type136 type1:infoflow6 ioctl 0x1234; auditallowxperm type0 type3:infoflow6 ioctl 0x1234; auditallowxperm type1 type4:infoflow6 ioctl 0x1234; auditallowxperm type2 type5:infoflow6 ioctl 0x1234; auditallowxperm type3 type6:infoflow6 ioctl 0x1234; auditallowxperm type4 type7:infoflow6 ioctl 0x1234; auditallowxperm type5 type8:infoflow6 ioctl 0x1234; auditallowxperm type6 type9:infoflow6 ioctl 0x1234; auditallowxperm type7 type10:infoflow6 ioctl 0x1234; auditallowxperm type8 type11:infoflow6 ioctl 0x1234; auditallowxperm type9 type12:infoflow6 ioctl 0x1234; auditallowxperm type10 type13:infoflow6 ioctl 0x1234; auditallowxperm type11 type14:infoflow6 ioctl 0x1234; auditallowxperm type12 type15:infoflow6 ioctl 0x1234; auditallowxperm type13 type16:infoflow6 ioctl 0x1234; auditallowxperm type14 type17:infoflow6 ioctl 0x1234; auditallowxperm type15 type18:infoflow6 ioctl 0x1234; auditallowxperm type16 type19:infoflow6 ioctl 0x1234; auditallowxperm type17 type20:infoflow6 ioctl 0x1234; auditallowxperm type18 type21:infoflow6 ioctl 0x1234; auditallowxperm type19 type22:infoflow6 ioctl 0x1234; auditallowxperm type20 type23:infoflow6 ioctl 0x1234; auditallowxperm type21 type24:infoflow6 ioctl 0x1234; auditallowxperm type22 type25:infoflow6 ioctl 0x1234; auditallowxperm type23 type26:infoflow6 ioctl 0x1234; auditallowxperm type24 type27:infoflow6 ioctl 0x1234; auditallowxperm type25 type28:infoflow6 ioctl 0x1234; auditallowxperm type26 type29:infoflow6 ioctl 0x1234; auditallowxperm type27 type30:infoflow6 ioctl 0x1234; auditallowxperm type28 type31:infoflow6 ioctl 0x1234; auditallowxperm type29 type32:infoflow6 ioctl 0x1234; auditallowxperm type30 type33:infoflow6 ioctl 0x1234; auditallowxperm type31 type34:infoflow6 ioctl 0x1234; auditallowxperm type32 type35:infoflow6 ioctl 0x1234; auditallowxperm type33 type36:infoflow6 ioctl 0x1234; auditallowxperm type34 type37:infoflow6 ioctl 0x1234; auditallowxperm type35 type38:infoflow6 ioctl 0x1234; auditallowxperm type36 type39:infoflow6 ioctl 0x1234; auditallowxperm type37 type40:infoflow6 ioctl 0x1234; auditallowxperm type38 type41:infoflow6 ioctl 0x1234; auditallowxperm type39 type42:infoflow6 ioctl 0x1234; auditallowxperm type40 type43:infoflow6 ioctl 0x1234; auditallowxperm type41 type44:infoflow6 ioctl 0x1234; auditallowxperm type42 type45:infoflow6 ioctl 0x1234; auditallowxperm type43 type46:infoflow6 ioctl 0x1234; # 191 neverallowxperm rules neverallowxperm type0 type4:infoflow6 ioctl 0x1234; neverallowxperm type1 type5:infoflow6 ioctl 0x1234; neverallowxperm type2 type6:infoflow6 ioctl 0x1234; neverallowxperm type3 type7:infoflow6 ioctl 0x1234; neverallowxperm type4 type8:infoflow6 ioctl 0x1234; neverallowxperm type5 type9:infoflow6 ioctl 0x1234; neverallowxperm type6 type10:infoflow6 ioctl 0x1234; neverallowxperm type7 type11:infoflow6 ioctl 0x1234; neverallowxperm type8 type12:infoflow6 ioctl 0x1234; neverallowxperm type9 type13:infoflow6 ioctl 0x1234; neverallowxperm type10 type14:infoflow6 ioctl 0x1234; neverallowxperm type11 type15:infoflow6 ioctl 0x1234; neverallowxperm type12 type16:infoflow6 ioctl 0x1234; neverallowxperm type13 type17:infoflow6 ioctl 0x1234; neverallowxperm type14 type18:infoflow6 ioctl 0x1234; neverallowxperm type15 type19:infoflow6 ioctl 0x1234; neverallowxperm type16 type20:infoflow6 ioctl 0x1234; neverallowxperm type17 type21:infoflow6 ioctl 0x1234; neverallowxperm type18 type22:infoflow6 ioctl 0x1234; neverallowxperm type19 type23:infoflow6 ioctl 0x1234; neverallowxperm type20 type24:infoflow6 ioctl 0x1234; neverallowxperm type21 type25:infoflow6 ioctl 0x1234; neverallowxperm type22 type26:infoflow6 ioctl 0x1234; neverallowxperm type23 type27:infoflow6 ioctl 0x1234; neverallowxperm type24 type28:infoflow6 ioctl 0x1234; neverallowxperm type25 type29:infoflow6 ioctl 0x1234; neverallowxperm type26 type30:infoflow6 ioctl 0x1234; neverallowxperm type27 type31:infoflow6 ioctl 0x1234; neverallowxperm type28 type32:infoflow6 ioctl 0x1234; neverallowxperm type29 type33:infoflow6 ioctl 0x1234; neverallowxperm type30 type34:infoflow6 ioctl 0x1234; neverallowxperm type31 type35:infoflow6 ioctl 0x1234; neverallowxperm type32 type36:infoflow6 ioctl 0x1234; neverallowxperm type33 type37:infoflow6 ioctl 0x1234; neverallowxperm type34 type38:infoflow6 ioctl 0x1234; neverallowxperm type35 type39:infoflow6 ioctl 0x1234; neverallowxperm type36 type40:infoflow6 ioctl 0x1234; neverallowxperm type37 type41:infoflow6 ioctl 0x1234; neverallowxperm type38 type42:infoflow6 ioctl 0x1234; neverallowxperm type39 type43:infoflow6 ioctl 0x1234; neverallowxperm type40 type44:infoflow6 ioctl 0x1234; neverallowxperm type41 type45:infoflow6 ioctl 0x1234; neverallowxperm type42 type46:infoflow6 ioctl 0x1234; neverallowxperm type43 type47:infoflow6 ioctl 0x1234; neverallowxperm type44 type48:infoflow6 ioctl 0x1234; neverallowxperm type45 type49:infoflow6 ioctl 0x1234; neverallowxperm type46 type50:infoflow6 ioctl 0x1234; neverallowxperm type47 type51:infoflow6 ioctl 0x1234; neverallowxperm type48 type52:infoflow6 ioctl 0x1234; neverallowxperm type49 type53:infoflow6 ioctl 0x1234; neverallowxperm type50 type54:infoflow6 ioctl 0x1234; neverallowxperm type51 type55:infoflow6 ioctl 0x1234; neverallowxperm type52 type56:infoflow6 ioctl 0x1234; neverallowxperm type53 type57:infoflow6 ioctl 0x1234; neverallowxperm type54 type58:infoflow6 ioctl 0x1234; neverallowxperm type55 type59:infoflow6 ioctl 0x1234; neverallowxperm type56 type60:infoflow6 ioctl 0x1234; neverallowxperm type57 type61:infoflow6 ioctl 0x1234; neverallowxperm type58 type62:infoflow6 ioctl 0x1234; neverallowxperm type59 type63:infoflow6 ioctl 0x1234; neverallowxperm type60 type64:infoflow6 ioctl 0x1234; neverallowxperm type61 type65:infoflow6 ioctl 0x1234; neverallowxperm type62 type66:infoflow6 ioctl 0x1234; neverallowxperm type63 type67:infoflow6 ioctl 0x1234; neverallowxperm type64 type68:infoflow6 ioctl 0x1234; neverallowxperm type65 type69:infoflow6 ioctl 0x1234; neverallowxperm type66 type70:infoflow6 ioctl 0x1234; neverallowxperm type67 type71:infoflow6 ioctl 0x1234; neverallowxperm type68 type72:infoflow6 ioctl 0x1234; neverallowxperm type69 type73:infoflow6 ioctl 0x1234; neverallowxperm type70 type74:infoflow6 ioctl 0x1234; neverallowxperm type71 type75:infoflow6 ioctl 0x1234; neverallowxperm type72 type76:infoflow6 ioctl 0x1234; neverallowxperm type73 type77:infoflow6 ioctl 0x1234; neverallowxperm type74 type78:infoflow6 ioctl 0x1234; neverallowxperm type75 type79:infoflow6 ioctl 0x1234; neverallowxperm type76 type80:infoflow6 ioctl 0x1234; neverallowxperm type77 type81:infoflow6 ioctl 0x1234; neverallowxperm type78 type82:infoflow6 ioctl 0x1234; neverallowxperm type79 type83:infoflow6 ioctl 0x1234; neverallowxperm type80 type84:infoflow6 ioctl 0x1234; neverallowxperm type81 type85:infoflow6 ioctl 0x1234; neverallowxperm type82 type86:infoflow6 ioctl 0x1234; neverallowxperm type83 type87:infoflow6 ioctl 0x1234; neverallowxperm type84 type88:infoflow6 ioctl 0x1234; neverallowxperm type85 type89:infoflow6 ioctl 0x1234; neverallowxperm type86 type90:infoflow6 ioctl 0x1234; neverallowxperm type87 type91:infoflow6 ioctl 0x1234; neverallowxperm type88 type92:infoflow6 ioctl 0x1234; neverallowxperm type89 type93:infoflow6 ioctl 0x1234; neverallowxperm type90 type94:infoflow6 ioctl 0x1234; neverallowxperm type91 type95:infoflow6 ioctl 0x1234; neverallowxperm type92 type96:infoflow6 ioctl 0x1234; neverallowxperm type93 type97:infoflow6 ioctl 0x1234; neverallowxperm type94 type98:infoflow6 ioctl 0x1234; neverallowxperm type95 type99:infoflow6 ioctl 0x1234; neverallowxperm type96 type100:infoflow6 ioctl 0x1234; neverallowxperm type97 type101:infoflow6 ioctl 0x1234; neverallowxperm type98 type102:infoflow6 ioctl 0x1234; neverallowxperm type99 type103:infoflow6 ioctl 0x1234; neverallowxperm type100 type104:infoflow6 ioctl 0x1234; neverallowxperm type101 type105:infoflow6 ioctl 0x1234; neverallowxperm type102 type106:infoflow6 ioctl 0x1234; neverallowxperm type103 type107:infoflow6 ioctl 0x1234; neverallowxperm type104 type108:infoflow6 ioctl 0x1234; neverallowxperm type105 type109:infoflow6 ioctl 0x1234; neverallowxperm type106 type110:infoflow6 ioctl 0x1234; neverallowxperm type107 type111:infoflow6 ioctl 0x1234; neverallowxperm type108 type112:infoflow6 ioctl 0x1234; neverallowxperm type109 type113:infoflow6 ioctl 0x1234; neverallowxperm type110 type114:infoflow6 ioctl 0x1234; neverallowxperm type111 type115:infoflow6 ioctl 0x1234; neverallowxperm type112 type116:infoflow6 ioctl 0x1234; neverallowxperm type113 type117:infoflow6 ioctl 0x1234; neverallowxperm type114 type118:infoflow6 ioctl 0x1234; neverallowxperm type115 type119:infoflow6 ioctl 0x1234; neverallowxperm type116 type120:infoflow6 ioctl 0x1234; neverallowxperm type117 type121:infoflow6 ioctl 0x1234; neverallowxperm type118 type122:infoflow6 ioctl 0x1234; neverallowxperm type119 type123:infoflow6 ioctl 0x1234; neverallowxperm type120 type124:infoflow6 ioctl 0x1234; neverallowxperm type121 type125:infoflow6 ioctl 0x1234; neverallowxperm type122 type126:infoflow6 ioctl 0x1234; neverallowxperm type123 type127:infoflow6 ioctl 0x1234; neverallowxperm type124 type128:infoflow6 ioctl 0x1234; neverallowxperm type125 type129:infoflow6 ioctl 0x1234; neverallowxperm type126 type130:infoflow6 ioctl 0x1234; neverallowxperm type127 type131:infoflow6 ioctl 0x1234; neverallowxperm type128 type132:infoflow6 ioctl 0x1234; neverallowxperm type129 type133:infoflow6 ioctl 0x1234; neverallowxperm type130 type134:infoflow6 ioctl 0x1234; neverallowxperm type131 type135:infoflow6 ioctl 0x1234; neverallowxperm type132 type136:infoflow6 ioctl 0x1234; neverallowxperm type133 type0:infoflow6 ioctl 0x1234; neverallowxperm type134 type1:infoflow6 ioctl 0x1234; neverallowxperm type135 type2:infoflow6 ioctl 0x1234; neverallowxperm type136 type3:infoflow6 ioctl 0x1234; neverallowxperm type0 type5:infoflow6 ioctl 0x1234; neverallowxperm type1 type6:infoflow6 ioctl 0x1234; neverallowxperm type2 type7:infoflow6 ioctl 0x1234; neverallowxperm type3 type8:infoflow6 ioctl 0x1234; neverallowxperm type4 type9:infoflow6 ioctl 0x1234; neverallowxperm type5 type10:infoflow6 ioctl 0x1234; neverallowxperm type6 type11:infoflow6 ioctl 0x1234; neverallowxperm type7 type12:infoflow6 ioctl 0x1234; neverallowxperm type8 type13:infoflow6 ioctl 0x1234; neverallowxperm type9 type14:infoflow6 ioctl 0x1234; neverallowxperm type10 type15:infoflow6 ioctl 0x1234; neverallowxperm type11 type16:infoflow6 ioctl 0x1234; neverallowxperm type12 type17:infoflow6 ioctl 0x1234; neverallowxperm type13 type18:infoflow6 ioctl 0x1234; neverallowxperm type14 type19:infoflow6 ioctl 0x1234; neverallowxperm type15 type20:infoflow6 ioctl 0x1234; neverallowxperm type16 type21:infoflow6 ioctl 0x1234; neverallowxperm type17 type22:infoflow6 ioctl 0x1234; neverallowxperm type18 type23:infoflow6 ioctl 0x1234; neverallowxperm type19 type24:infoflow6 ioctl 0x1234; neverallowxperm type20 type25:infoflow6 ioctl 0x1234; neverallowxperm type21 type26:infoflow6 ioctl 0x1234; neverallowxperm type22 type27:infoflow6 ioctl 0x1234; neverallowxperm type23 type28:infoflow6 ioctl 0x1234; neverallowxperm type24 type29:infoflow6 ioctl 0x1234; neverallowxperm type25 type30:infoflow6 ioctl 0x1234; neverallowxperm type26 type31:infoflow6 ioctl 0x1234; neverallowxperm type27 type32:infoflow6 ioctl 0x1234; neverallowxperm type28 type33:infoflow6 ioctl 0x1234; neverallowxperm type29 type34:infoflow6 ioctl 0x1234; neverallowxperm type30 type35:infoflow6 ioctl 0x1234; neverallowxperm type31 type36:infoflow6 ioctl 0x1234; neverallowxperm type32 type37:infoflow6 ioctl 0x1234; neverallowxperm type33 type38:infoflow6 ioctl 0x1234; neverallowxperm type34 type39:infoflow6 ioctl 0x1234; neverallowxperm type35 type40:infoflow6 ioctl 0x1234; neverallowxperm type36 type41:infoflow6 ioctl 0x1234; neverallowxperm type37 type42:infoflow6 ioctl 0x1234; neverallowxperm type38 type43:infoflow6 ioctl 0x1234; neverallowxperm type39 type44:infoflow6 ioctl 0x1234; neverallowxperm type40 type45:infoflow6 ioctl 0x1234; neverallowxperm type41 type46:infoflow6 ioctl 0x1234; neverallowxperm type42 type47:infoflow6 ioctl 0x1234; neverallowxperm type43 type48:infoflow6 ioctl 0x1234; neverallowxperm type44 type49:infoflow6 ioctl 0x1234; neverallowxperm type45 type50:infoflow6 ioctl 0x1234; neverallowxperm type46 type51:infoflow6 ioctl 0x1234; neverallowxperm type47 type52:infoflow6 ioctl 0x1234; neverallowxperm type48 type53:infoflow6 ioctl 0x1234; neverallowxperm type49 type54:infoflow6 ioctl 0x1234; neverallowxperm type50 type55:infoflow6 ioctl 0x1234; neverallowxperm type51 type56:infoflow6 ioctl 0x1234; neverallowxperm type52 type57:infoflow6 ioctl 0x1234; neverallowxperm type53 type58:infoflow6 ioctl 0x1234; # 193 dontauditxperm rules dontauditxperm type0 type5:infoflow6 ioctl 0x1234; dontauditxperm type1 type6:infoflow6 ioctl 0x1234; dontauditxperm type2 type7:infoflow6 ioctl 0x1234; dontauditxperm type3 type8:infoflow6 ioctl 0x1234; dontauditxperm type4 type9:infoflow6 ioctl 0x1234; dontauditxperm type5 type10:infoflow6 ioctl 0x1234; dontauditxperm type6 type11:infoflow6 ioctl 0x1234; dontauditxperm type7 type12:infoflow6 ioctl 0x1234; dontauditxperm type8 type13:infoflow6 ioctl 0x1234; dontauditxperm type9 type14:infoflow6 ioctl 0x1234; dontauditxperm type10 type15:infoflow6 ioctl 0x1234; dontauditxperm type11 type16:infoflow6 ioctl 0x1234; dontauditxperm type12 type17:infoflow6 ioctl 0x1234; dontauditxperm type13 type18:infoflow6 ioctl 0x1234; dontauditxperm type14 type19:infoflow6 ioctl 0x1234; dontauditxperm type15 type20:infoflow6 ioctl 0x1234; dontauditxperm type16 type21:infoflow6 ioctl 0x1234; dontauditxperm type17 type22:infoflow6 ioctl 0x1234; dontauditxperm type18 type23:infoflow6 ioctl 0x1234; dontauditxperm type19 type24:infoflow6 ioctl 0x1234; dontauditxperm type20 type25:infoflow6 ioctl 0x1234; dontauditxperm type21 type26:infoflow6 ioctl 0x1234; dontauditxperm type22 type27:infoflow6 ioctl 0x1234; dontauditxperm type23 type28:infoflow6 ioctl 0x1234; dontauditxperm type24 type29:infoflow6 ioctl 0x1234; dontauditxperm type25 type30:infoflow6 ioctl 0x1234; dontauditxperm type26 type31:infoflow6 ioctl 0x1234; dontauditxperm type27 type32:infoflow6 ioctl 0x1234; dontauditxperm type28 type33:infoflow6 ioctl 0x1234; dontauditxperm type29 type34:infoflow6 ioctl 0x1234; dontauditxperm type30 type35:infoflow6 ioctl 0x1234; dontauditxperm type31 type36:infoflow6 ioctl 0x1234; dontauditxperm type32 type37:infoflow6 ioctl 0x1234; dontauditxperm type33 type38:infoflow6 ioctl 0x1234; dontauditxperm type34 type39:infoflow6 ioctl 0x1234; dontauditxperm type35 type40:infoflow6 ioctl 0x1234; dontauditxperm type36 type41:infoflow6 ioctl 0x1234; dontauditxperm type37 type42:infoflow6 ioctl 0x1234; dontauditxperm type38 type43:infoflow6 ioctl 0x1234; dontauditxperm type39 type44:infoflow6 ioctl 0x1234; dontauditxperm type40 type45:infoflow6 ioctl 0x1234; dontauditxperm type41 type46:infoflow6 ioctl 0x1234; dontauditxperm type42 type47:infoflow6 ioctl 0x1234; dontauditxperm type43 type48:infoflow6 ioctl 0x1234; dontauditxperm type44 type49:infoflow6 ioctl 0x1234; dontauditxperm type45 type50:infoflow6 ioctl 0x1234; dontauditxperm type46 type51:infoflow6 ioctl 0x1234; dontauditxperm type47 type52:infoflow6 ioctl 0x1234; dontauditxperm type48 type53:infoflow6 ioctl 0x1234; dontauditxperm type49 type54:infoflow6 ioctl 0x1234; dontauditxperm type50 type55:infoflow6 ioctl 0x1234; dontauditxperm type51 type56:infoflow6 ioctl 0x1234; dontauditxperm type52 type57:infoflow6 ioctl 0x1234; dontauditxperm type53 type58:infoflow6 ioctl 0x1234; dontauditxperm type54 type59:infoflow6 ioctl 0x1234; dontauditxperm type55 type60:infoflow6 ioctl 0x1234; dontauditxperm type56 type61:infoflow6 ioctl 0x1234; dontauditxperm type57 type62:infoflow6 ioctl 0x1234; dontauditxperm type58 type63:infoflow6 ioctl 0x1234; dontauditxperm type59 type64:infoflow6 ioctl 0x1234; dontauditxperm type60 type65:infoflow6 ioctl 0x1234; dontauditxperm type61 type66:infoflow6 ioctl 0x1234; dontauditxperm type62 type67:infoflow6 ioctl 0x1234; dontauditxperm type63 type68:infoflow6 ioctl 0x1234; dontauditxperm type64 type69:infoflow6 ioctl 0x1234; dontauditxperm type65 type70:infoflow6 ioctl 0x1234; dontauditxperm type66 type71:infoflow6 ioctl 0x1234; dontauditxperm type67 type72:infoflow6 ioctl 0x1234; dontauditxperm type68 type73:infoflow6 ioctl 0x1234; dontauditxperm type69 type74:infoflow6 ioctl 0x1234; dontauditxperm type70 type75:infoflow6 ioctl 0x1234; dontauditxperm type71 type76:infoflow6 ioctl 0x1234; dontauditxperm type72 type77:infoflow6 ioctl 0x1234; dontauditxperm type73 type78:infoflow6 ioctl 0x1234; dontauditxperm type74 type79:infoflow6 ioctl 0x1234; dontauditxperm type75 type80:infoflow6 ioctl 0x1234; dontauditxperm type76 type81:infoflow6 ioctl 0x1234; dontauditxperm type77 type82:infoflow6 ioctl 0x1234; dontauditxperm type78 type83:infoflow6 ioctl 0x1234; dontauditxperm type79 type84:infoflow6 ioctl 0x1234; dontauditxperm type80 type85:infoflow6 ioctl 0x1234; dontauditxperm type81 type86:infoflow6 ioctl 0x1234; dontauditxperm type82 type87:infoflow6 ioctl 0x1234; dontauditxperm type83 type88:infoflow6 ioctl 0x1234; dontauditxperm type84 type89:infoflow6 ioctl 0x1234; dontauditxperm type85 type90:infoflow6 ioctl 0x1234; dontauditxperm type86 type91:infoflow6 ioctl 0x1234; dontauditxperm type87 type92:infoflow6 ioctl 0x1234; dontauditxperm type88 type93:infoflow6 ioctl 0x1234; dontauditxperm type89 type94:infoflow6 ioctl 0x1234; dontauditxperm type90 type95:infoflow6 ioctl 0x1234; dontauditxperm type91 type96:infoflow6 ioctl 0x1234; dontauditxperm type92 type97:infoflow6 ioctl 0x1234; dontauditxperm type93 type98:infoflow6 ioctl 0x1234; dontauditxperm type94 type99:infoflow6 ioctl 0x1234; dontauditxperm type95 type100:infoflow6 ioctl 0x1234; dontauditxperm type96 type101:infoflow6 ioctl 0x1234; dontauditxperm type97 type102:infoflow6 ioctl 0x1234; dontauditxperm type98 type103:infoflow6 ioctl 0x1234; dontauditxperm type99 type104:infoflow6 ioctl 0x1234; dontauditxperm type100 type105:infoflow6 ioctl 0x1234; dontauditxperm type101 type106:infoflow6 ioctl 0x1234; dontauditxperm type102 type107:infoflow6 ioctl 0x1234; dontauditxperm type103 type108:infoflow6 ioctl 0x1234; dontauditxperm type104 type109:infoflow6 ioctl 0x1234; dontauditxperm type105 type110:infoflow6 ioctl 0x1234; dontauditxperm type106 type111:infoflow6 ioctl 0x1234; dontauditxperm type107 type112:infoflow6 ioctl 0x1234; dontauditxperm type108 type113:infoflow6 ioctl 0x1234; dontauditxperm type109 type114:infoflow6 ioctl 0x1234; dontauditxperm type110 type115:infoflow6 ioctl 0x1234; dontauditxperm type111 type116:infoflow6 ioctl 0x1234; dontauditxperm type112 type117:infoflow6 ioctl 0x1234; dontauditxperm type113 type118:infoflow6 ioctl 0x1234; dontauditxperm type114 type119:infoflow6 ioctl 0x1234; dontauditxperm type115 type120:infoflow6 ioctl 0x1234; dontauditxperm type116 type121:infoflow6 ioctl 0x1234; dontauditxperm type117 type122:infoflow6 ioctl 0x1234; dontauditxperm type118 type123:infoflow6 ioctl 0x1234; dontauditxperm type119 type124:infoflow6 ioctl 0x1234; dontauditxperm type120 type125:infoflow6 ioctl 0x1234; dontauditxperm type121 type126:infoflow6 ioctl 0x1234; dontauditxperm type122 type127:infoflow6 ioctl 0x1234; dontauditxperm type123 type128:infoflow6 ioctl 0x1234; dontauditxperm type124 type129:infoflow6 ioctl 0x1234; dontauditxperm type125 type130:infoflow6 ioctl 0x1234; dontauditxperm type126 type131:infoflow6 ioctl 0x1234; dontauditxperm type127 type132:infoflow6 ioctl 0x1234; dontauditxperm type128 type133:infoflow6 ioctl 0x1234; dontauditxperm type129 type134:infoflow6 ioctl 0x1234; dontauditxperm type130 type135:infoflow6 ioctl 0x1234; dontauditxperm type131 type136:infoflow6 ioctl 0x1234; dontauditxperm type132 type0:infoflow6 ioctl 0x1234; dontauditxperm type133 type1:infoflow6 ioctl 0x1234; dontauditxperm type134 type2:infoflow6 ioctl 0x1234; dontauditxperm type135 type3:infoflow6 ioctl 0x1234; dontauditxperm type136 type4:infoflow6 ioctl 0x1234; dontauditxperm type0 type6:infoflow6 ioctl 0x1234; dontauditxperm type1 type7:infoflow6 ioctl 0x1234; dontauditxperm type2 type8:infoflow6 ioctl 0x1234; dontauditxperm type3 type9:infoflow6 ioctl 0x1234; dontauditxperm type4 type10:infoflow6 ioctl 0x1234; dontauditxperm type5 type11:infoflow6 ioctl 0x1234; dontauditxperm type6 type12:infoflow6 ioctl 0x1234; dontauditxperm type7 type13:infoflow6 ioctl 0x1234; dontauditxperm type8 type14:infoflow6 ioctl 0x1234; dontauditxperm type9 type15:infoflow6 ioctl 0x1234; dontauditxperm type10 type16:infoflow6 ioctl 0x1234; dontauditxperm type11 type17:infoflow6 ioctl 0x1234; dontauditxperm type12 type18:infoflow6 ioctl 0x1234; dontauditxperm type13 type19:infoflow6 ioctl 0x1234; dontauditxperm type14 type20:infoflow6 ioctl 0x1234; dontauditxperm type15 type21:infoflow6 ioctl 0x1234; dontauditxperm type16 type22:infoflow6 ioctl 0x1234; dontauditxperm type17 type23:infoflow6 ioctl 0x1234; dontauditxperm type18 type24:infoflow6 ioctl 0x1234; dontauditxperm type19 type25:infoflow6 ioctl 0x1234; dontauditxperm type20 type26:infoflow6 ioctl 0x1234; dontauditxperm type21 type27:infoflow6 ioctl 0x1234; dontauditxperm type22 type28:infoflow6 ioctl 0x1234; dontauditxperm type23 type29:infoflow6 ioctl 0x1234; dontauditxperm type24 type30:infoflow6 ioctl 0x1234; dontauditxperm type25 type31:infoflow6 ioctl 0x1234; dontauditxperm type26 type32:infoflow6 ioctl 0x1234; dontauditxperm type27 type33:infoflow6 ioctl 0x1234; dontauditxperm type28 type34:infoflow6 ioctl 0x1234; dontauditxperm type29 type35:infoflow6 ioctl 0x1234; dontauditxperm type30 type36:infoflow6 ioctl 0x1234; dontauditxperm type31 type37:infoflow6 ioctl 0x1234; dontauditxperm type32 type38:infoflow6 ioctl 0x1234; dontauditxperm type33 type39:infoflow6 ioctl 0x1234; dontauditxperm type34 type40:infoflow6 ioctl 0x1234; dontauditxperm type35 type41:infoflow6 ioctl 0x1234; dontauditxperm type36 type42:infoflow6 ioctl 0x1234; dontauditxperm type37 type43:infoflow6 ioctl 0x1234; dontauditxperm type38 type44:infoflow6 ioctl 0x1234; dontauditxperm type39 type45:infoflow6 ioctl 0x1234; dontauditxperm type40 type46:infoflow6 ioctl 0x1234; dontauditxperm type41 type47:infoflow6 ioctl 0x1234; dontauditxperm type42 type48:infoflow6 ioctl 0x1234; dontauditxperm type43 type49:infoflow6 ioctl 0x1234; dontauditxperm type44 type50:infoflow6 ioctl 0x1234; dontauditxperm type45 type51:infoflow6 ioctl 0x1234; dontauditxperm type46 type52:infoflow6 ioctl 0x1234; dontauditxperm type47 type53:infoflow6 ioctl 0x1234; dontauditxperm type48 type54:infoflow6 ioctl 0x1234; dontauditxperm type49 type55:infoflow6 ioctl 0x1234; dontauditxperm type50 type56:infoflow6 ioctl 0x1234; dontauditxperm type51 type57:infoflow6 ioctl 0x1234; dontauditxperm type52 type58:infoflow6 ioctl 0x1234; dontauditxperm type53 type59:infoflow6 ioctl 0x1234; dontauditxperm type54 type60:infoflow6 ioctl 0x1234; dontauditxperm type55 type61:infoflow6 ioctl 0x1234; ################################################################################ # 101 users user user0 roles role0 level s4:c5 range s4:c5; user user1 roles role0 level s4:c5 range s4:c5; user user2 roles role0 level s4:c5 range s4:c5; user user3 roles role0 level s4:c5 range s4:c5; user user4 roles role0 level s4:c5 range s4:c5; user user5 roles role0 level s4:c5 range s4:c5; user user6 roles role0 level s4:c5 range s4:c5; user user7 roles role0 level s4:c5 range s4:c5; user user8 roles role0 level s4:c5 range s4:c5; user user9 roles role0 level s4:c5 range s4:c5; user user10 roles role0 level s4:c5 range s4:c5; user user11 roles role0 level s4:c5 range s4:c5; user user12 roles role0 level s4:c5 range s4:c5; user user13 roles role0 level s4:c5 range s4:c5; user user14 roles role0 level s4:c5 range s4:c5; user user15 roles role0 level s4:c5 range s4:c5; user user16 roles role0 level s4:c5 range s4:c5; user user17 roles role0 level s4:c5 range s4:c5; user user18 roles role0 level s4:c5 range s4:c5; user user19 roles role0 level s4:c5 range s4:c5; user user20 roles role0 level s4:c5 range s4:c5; user user21 roles role0 level s4:c5 range s4:c5; user user22 roles role0 level s4:c5 range s4:c5; user user23 roles role0 level s4:c5 range s4:c5; user user24 roles role0 level s4:c5 range s4:c5; user user25 roles role0 level s4:c5 range s4:c5; user user26 roles role0 level s4:c5 range s4:c5; user user27 roles role0 level s4:c5 range s4:c5; user user28 roles role0 level s4:c5 range s4:c5; user user29 roles role0 level s4:c5 range s4:c5; user user30 roles role0 level s4:c5 range s4:c5; user user31 roles role0 level s4:c5 range s4:c5; user user32 roles role0 level s4:c5 range s4:c5; user user33 roles role0 level s4:c5 range s4:c5; user user34 roles role0 level s4:c5 range s4:c5; user user35 roles role0 level s4:c5 range s4:c5; user user36 roles role0 level s4:c5 range s4:c5; user user37 roles role0 level s4:c5 range s4:c5; user user38 roles role0 level s4:c5 range s4:c5; user user39 roles role0 level s4:c5 range s4:c5; user user40 roles role0 level s4:c5 range s4:c5; user user41 roles role0 level s4:c5 range s4:c5; user user42 roles role0 level s4:c5 range s4:c5; user user43 roles role0 level s4:c5 range s4:c5; user user44 roles role0 level s4:c5 range s4:c5; user user45 roles role0 level s4:c5 range s4:c5; user user46 roles role0 level s4:c5 range s4:c5; user user47 roles role0 level s4:c5 range s4:c5; user user48 roles role0 level s4:c5 range s4:c5; user user49 roles role0 level s4:c5 range s4:c5; user user50 roles role0 level s4:c5 range s4:c5; user user51 roles role0 level s4:c5 range s4:c5; user user52 roles role0 level s4:c5 range s4:c5; user user53 roles role0 level s4:c5 range s4:c5; user user54 roles role0 level s4:c5 range s4:c5; user user55 roles role0 level s4:c5 range s4:c5; user user56 roles role0 level s4:c5 range s4:c5; user user57 roles role0 level s4:c5 range s4:c5; user user58 roles role0 level s4:c5 range s4:c5; user user59 roles role0 level s4:c5 range s4:c5; user user60 roles role0 level s4:c5 range s4:c5; user user61 roles role0 level s4:c5 range s4:c5; user user62 roles role0 level s4:c5 range s4:c5; user user63 roles role0 level s4:c5 range s4:c5; user user64 roles role0 level s4:c5 range s4:c5; user user65 roles role0 level s4:c5 range s4:c5; user user66 roles role0 level s4:c5 range s4:c5; user user67 roles role0 level s4:c5 range s4:c5; user user68 roles role0 level s4:c5 range s4:c5; user user69 roles role0 level s4:c5 range s4:c5; user user70 roles role0 level s4:c5 range s4:c5; user user71 roles role0 level s4:c5 range s4:c5; user user72 roles role0 level s4:c5 range s4:c5; user user73 roles role0 level s4:c5 range s4:c5; user user74 roles role0 level s4:c5 range s4:c5; user user75 roles role0 level s4:c5 range s4:c5; user user76 roles role0 level s4:c5 range s4:c5; user user77 roles role0 level s4:c5 range s4:c5; user user78 roles role0 level s4:c5 range s4:c5; user user79 roles role0 level s4:c5 range s4:c5; user user80 roles role0 level s4:c5 range s4:c5; user user81 roles role0 level s4:c5 range s4:c5; user user82 roles role0 level s4:c5 range s4:c5; user user83 roles role0 level s4:c5 range s4:c5; user user84 roles role0 level s4:c5 range s4:c5; user user85 roles role0 level s4:c5 range s4:c5; user user86 roles role0 level s4:c5 range s4:c5; user user87 roles role0 level s4:c5 range s4:c5; user user88 roles role0 level s4:c5 range s4:c5; user user89 roles role0 level s4:c5 range s4:c5; user user90 roles role0 level s4:c5 range s4:c5; user user91 roles role0 level s4:c5 range s4:c5; user user92 roles role0 level s4:c5 range s4:c5; user user93 roles role0 level s4:c5 range s4:c5; user user94 roles role0 level s4:c5 range s4:c5; user user95 roles role0 level s4:c5 range s4:c5; user user96 roles role0 level s4:c5 range s4:c5; user user97 roles role0 level s4:c5 range s4:c5; user user98 roles role0 level s4:c5 range s4:c5; user user99 roles role0 level s4:c5 range s4:c5; user user100 roles role0 level s4:c5 range s4:c5; # 19 normal constraints constrain infoflow low_w ((u1 eq u2) or (t1 == attr1)); constrain infoflow low_r ((u1 eq u2) or (t1 == attr2)); constrain infoflow low_none ((u1 eq u2) or (t1 == attr3)); constrain infoflow2 med_r ((u1 eq u2) or (t1 == attr4)); constrain infoflow2 med_w ((u1 eq u2) or (t1 == attr5)); constrain infoflow2 med_none ((u1 eq u2) or (t1 == attr6)); constrain infoflow2 med_both ((u1 eq u2) or (t1 == attr7)); constrain infoflow2 med_fifth ((u1 eq u2) or (t1 == attr8)); constrain infoflow2 super_r ((u1 eq u2) or (t1 == attr9)); constrain infoflow2 super_w ((u1 eq u2) or (t1 == attr10)); constrain infoflow4 hi_w ((u1 eq u2) or (t1 == attr11)); constrain infoflow4 hi_r ((u1 eq u2) or (t1 == attr12)); constrain infoflow4 hi_third ((u1 eq u2) or (t1 == attr13)); constrain infoflow4 hi_fourth ((u1 eq u2) or (t1 == attr14)); constrain infoflow4 hi_fifth ((u1 eq u2) or (t1 == attr15)); constrain infoflow4 hi_sixth ((u1 eq u2) or (t1 == attr16)); constrain infoflow4 hi_seventh ((u1 eq u2) or (t1 == attr17)); constrain infoflow4 super_both ((u1 eq u2) or (t1 == attr18)); constrain infoflow5 hi_w ((u1 eq u2) or (t1 == attr19)); # 5 validatetrans validatetrans { infoflow infoflow2 infoflow3 infoflow4 infoflow5 } (u1 == u2); # 11 initial SIDs sid sid_one user0:role0:type0:s4:c5 sid sid_two user0:role0:type0:s4:c5 sid sid_three user0:role0:type0:s4:c5 sid sid_four user0:role0:type0:s4:c5 sid sid_five user0:role0:type0:s4:c5 sid sid_six user0:role0:type0:s4:c5 sid sid_seven user0:role0:type0:s4:c5 sid sid_eight user0:role0:type0:s4:c5 sid sid_nine user0:role0:type0:s4:c5 sid sid_ten user0:role0:type0:s4:c5 sid sid_eleven user0:role0:type0:s4:c5 # 149 fs_use fs_use_trans fs0 user0:object_r:type0:s4:c5; fs_use_xattr fs1 user0:object_r:type0:s4:c5; fs_use_task fs2 user0:object_r:type0:s4:c5; fs_use_trans fs3 user0:object_r:type0:s4:c5; fs_use_xattr fs4 user0:object_r:type0:s4:c5; fs_use_task fs5 user0:object_r:type0:s4:c5; fs_use_trans fs6 user0:object_r:type0:s4:c5; fs_use_xattr fs7 user0:object_r:type0:s4:c5; fs_use_task fs8 user0:object_r:type0:s4:c5; fs_use_trans fs9 user0:object_r:type0:s4:c5; fs_use_xattr fs10 user0:object_r:type0:s4:c5; fs_use_task fs11 user0:object_r:type0:s4:c5; fs_use_trans fs12 user0:object_r:type0:s4:c5; fs_use_xattr fs13 user0:object_r:type0:s4:c5; fs_use_task fs14 user0:object_r:type0:s4:c5; fs_use_trans fs15 user0:object_r:type0:s4:c5; fs_use_xattr fs16 user0:object_r:type0:s4:c5; fs_use_task fs17 user0:object_r:type0:s4:c5; fs_use_trans fs18 user0:object_r:type0:s4:c5; fs_use_xattr fs19 user0:object_r:type0:s4:c5; fs_use_task fs20 user0:object_r:type0:s4:c5; fs_use_trans fs21 user0:object_r:type0:s4:c5; fs_use_xattr fs22 user0:object_r:type0:s4:c5; fs_use_task fs23 user0:object_r:type0:s4:c5; fs_use_trans fs24 user0:object_r:type0:s4:c5; fs_use_xattr fs25 user0:object_r:type0:s4:c5; fs_use_task fs26 user0:object_r:type0:s4:c5; fs_use_trans fs27 user0:object_r:type0:s4:c5; fs_use_xattr fs28 user0:object_r:type0:s4:c5; fs_use_task fs29 user0:object_r:type0:s4:c5; fs_use_trans fs30 user0:object_r:type0:s4:c5; fs_use_xattr fs31 user0:object_r:type0:s4:c5; fs_use_task fs32 user0:object_r:type0:s4:c5; fs_use_trans fs33 user0:object_r:type0:s4:c5; fs_use_xattr fs34 user0:object_r:type0:s4:c5; fs_use_task fs35 user0:object_r:type0:s4:c5; fs_use_trans fs36 user0:object_r:type0:s4:c5; fs_use_xattr fs37 user0:object_r:type0:s4:c5; fs_use_task fs38 user0:object_r:type0:s4:c5; fs_use_trans fs39 user0:object_r:type0:s4:c5; fs_use_xattr fs40 user0:object_r:type0:s4:c5; fs_use_task fs41 user0:object_r:type0:s4:c5; fs_use_trans fs42 user0:object_r:type0:s4:c5; fs_use_xattr fs43 user0:object_r:type0:s4:c5; fs_use_task fs44 user0:object_r:type0:s4:c5; fs_use_trans fs45 user0:object_r:type0:s4:c5; fs_use_xattr fs46 user0:object_r:type0:s4:c5; fs_use_task fs47 user0:object_r:type0:s4:c5; fs_use_trans fs48 user0:object_r:type0:s4:c5; fs_use_xattr fs49 user0:object_r:type0:s4:c5; fs_use_task fs50 user0:object_r:type0:s4:c5; fs_use_trans fs51 user0:object_r:type0:s4:c5; fs_use_xattr fs52 user0:object_r:type0:s4:c5; fs_use_task fs53 user0:object_r:type0:s4:c5; fs_use_trans fs54 user0:object_r:type0:s4:c5; fs_use_xattr fs55 user0:object_r:type0:s4:c5; fs_use_task fs56 user0:object_r:type0:s4:c5; fs_use_trans fs57 user0:object_r:type0:s4:c5; fs_use_xattr fs58 user0:object_r:type0:s4:c5; fs_use_task fs59 user0:object_r:type0:s4:c5; fs_use_trans fs60 user0:object_r:type0:s4:c5; fs_use_xattr fs61 user0:object_r:type0:s4:c5; fs_use_task fs62 user0:object_r:type0:s4:c5; fs_use_trans fs63 user0:object_r:type0:s4:c5; fs_use_xattr fs64 user0:object_r:type0:s4:c5; fs_use_task fs65 user0:object_r:type0:s4:c5; fs_use_trans fs66 user0:object_r:type0:s4:c5; fs_use_xattr fs67 user0:object_r:type0:s4:c5; fs_use_task fs68 user0:object_r:type0:s4:c5; fs_use_trans fs69 user0:object_r:type0:s4:c5; fs_use_xattr fs70 user0:object_r:type0:s4:c5; fs_use_task fs71 user0:object_r:type0:s4:c5; fs_use_trans fs72 user0:object_r:type0:s4:c5; fs_use_xattr fs73 user0:object_r:type0:s4:c5; fs_use_task fs74 user0:object_r:type0:s4:c5; fs_use_trans fs75 user0:object_r:type0:s4:c5; fs_use_xattr fs76 user0:object_r:type0:s4:c5; fs_use_task fs77 user0:object_r:type0:s4:c5; fs_use_trans fs78 user0:object_r:type0:s4:c5; fs_use_xattr fs79 user0:object_r:type0:s4:c5; fs_use_task fs80 user0:object_r:type0:s4:c5; fs_use_trans fs81 user0:object_r:type0:s4:c5; fs_use_xattr fs82 user0:object_r:type0:s4:c5; fs_use_task fs83 user0:object_r:type0:s4:c5; fs_use_trans fs84 user0:object_r:type0:s4:c5; fs_use_xattr fs85 user0:object_r:type0:s4:c5; fs_use_task fs86 user0:object_r:type0:s4:c5; fs_use_trans fs87 user0:object_r:type0:s4:c5; fs_use_xattr fs88 user0:object_r:type0:s4:c5; fs_use_task fs89 user0:object_r:type0:s4:c5; fs_use_trans fs90 user0:object_r:type0:s4:c5; fs_use_xattr fs91 user0:object_r:type0:s4:c5; fs_use_task fs92 user0:object_r:type0:s4:c5; fs_use_trans fs93 user0:object_r:type0:s4:c5; fs_use_xattr fs94 user0:object_r:type0:s4:c5; fs_use_task fs95 user0:object_r:type0:s4:c5; fs_use_trans fs96 user0:object_r:type0:s4:c5; fs_use_xattr fs97 user0:object_r:type0:s4:c5; fs_use_task fs98 user0:object_r:type0:s4:c5; fs_use_trans fs99 user0:object_r:type0:s4:c5; fs_use_xattr fs100 user0:object_r:type0:s4:c5; fs_use_task fs101 user0:object_r:type0:s4:c5; fs_use_trans fs102 user0:object_r:type0:s4:c5; fs_use_xattr fs103 user0:object_r:type0:s4:c5; fs_use_task fs104 user0:object_r:type0:s4:c5; fs_use_trans fs105 user0:object_r:type0:s4:c5; fs_use_xattr fs106 user0:object_r:type0:s4:c5; fs_use_task fs107 user0:object_r:type0:s4:c5; fs_use_trans fs108 user0:object_r:type0:s4:c5; fs_use_xattr fs109 user0:object_r:type0:s4:c5; fs_use_task fs110 user0:object_r:type0:s4:c5; fs_use_trans fs111 user0:object_r:type0:s4:c5; fs_use_xattr fs112 user0:object_r:type0:s4:c5; fs_use_task fs113 user0:object_r:type0:s4:c5; fs_use_trans fs114 user0:object_r:type0:s4:c5; fs_use_xattr fs115 user0:object_r:type0:s4:c5; fs_use_task fs116 user0:object_r:type0:s4:c5; fs_use_trans fs117 user0:object_r:type0:s4:c5; fs_use_xattr fs118 user0:object_r:type0:s4:c5; fs_use_task fs119 user0:object_r:type0:s4:c5; fs_use_trans fs120 user0:object_r:type0:s4:c5; fs_use_xattr fs121 user0:object_r:type0:s4:c5; fs_use_task fs122 user0:object_r:type0:s4:c5; fs_use_trans fs123 user0:object_r:type0:s4:c5; fs_use_xattr fs124 user0:object_r:type0:s4:c5; fs_use_task fs125 user0:object_r:type0:s4:c5; fs_use_trans fs126 user0:object_r:type0:s4:c5; fs_use_xattr fs127 user0:object_r:type0:s4:c5; fs_use_task fs128 user0:object_r:type0:s4:c5; fs_use_trans fs129 user0:object_r:type0:s4:c5; fs_use_xattr fs130 user0:object_r:type0:s4:c5; fs_use_task fs131 user0:object_r:type0:s4:c5; fs_use_trans fs132 user0:object_r:type0:s4:c5; fs_use_xattr fs133 user0:object_r:type0:s4:c5; fs_use_task fs134 user0:object_r:type0:s4:c5; fs_use_trans fs135 user0:object_r:type0:s4:c5; fs_use_xattr fs136 user0:object_r:type0:s4:c5; fs_use_task fs137 user0:object_r:type0:s4:c5; fs_use_trans fs138 user0:object_r:type0:s4:c5; fs_use_xattr fs139 user0:object_r:type0:s4:c5; fs_use_task fs140 user0:object_r:type0:s4:c5; fs_use_trans fs141 user0:object_r:type0:s4:c5; fs_use_xattr fs142 user0:object_r:type0:s4:c5; fs_use_task fs143 user0:object_r:type0:s4:c5; fs_use_trans fs144 user0:object_r:type0:s4:c5; fs_use_xattr fs145 user0:object_r:type0:s4:c5; fs_use_task fs146 user0:object_r:type0:s4:c5; fs_use_trans fs147 user0:object_r:type0:s4:c5; fs_use_xattr fs148 user0:object_r:type0:s4:c5; # 151 genfscon genfscon fs149 / user0:object_r:type0:s3 genfscon fs150 / user0:object_r:type0:s3 genfscon fs151 / user0:object_r:type0:s3 genfscon fs152 / user0:object_r:type0:s3 genfscon fs153 / user0:object_r:type0:s3 genfscon fs154 / user0:object_r:type0:s3 genfscon fs155 / user0:object_r:type0:s3 genfscon fs156 / user0:object_r:type0:s3 genfscon fs157 / user0:object_r:type0:s3 genfscon fs158 / user0:object_r:type0:s3 genfscon fs159 / user0:object_r:type0:s3 genfscon fs160 / user0:object_r:type0:s3 genfscon fs161 / user0:object_r:type0:s3 genfscon fs162 / user0:object_r:type0:s3 genfscon fs163 / user0:object_r:type0:s3 genfscon fs164 / user0:object_r:type0:s3 genfscon fs165 / user0:object_r:type0:s3 genfscon fs166 / user0:object_r:type0:s3 genfscon fs167 / user0:object_r:type0:s3 genfscon fs168 / user0:object_r:type0:s3 genfscon fs169 / user0:object_r:type0:s3 genfscon fs170 / user0:object_r:type0:s3 genfscon fs171 / user0:object_r:type0:s3 genfscon fs172 / user0:object_r:type0:s3 genfscon fs173 / user0:object_r:type0:s3 genfscon fs174 / user0:object_r:type0:s3 genfscon fs175 / user0:object_r:type0:s3 genfscon fs176 / user0:object_r:type0:s3 genfscon fs177 / user0:object_r:type0:s3 genfscon fs178 / user0:object_r:type0:s3 genfscon fs179 / user0:object_r:type0:s3 genfscon fs180 / user0:object_r:type0:s3 genfscon fs181 / user0:object_r:type0:s3 genfscon fs182 / user0:object_r:type0:s3 genfscon fs183 / user0:object_r:type0:s3 genfscon fs184 / user0:object_r:type0:s3 genfscon fs185 / user0:object_r:type0:s3 genfscon fs186 / user0:object_r:type0:s3 genfscon fs187 / user0:object_r:type0:s3 genfscon fs188 / user0:object_r:type0:s3 genfscon fs189 / user0:object_r:type0:s3 genfscon fs190 / user0:object_r:type0:s3 genfscon fs191 / user0:object_r:type0:s3 genfscon fs192 / user0:object_r:type0:s3 genfscon fs193 / user0:object_r:type0:s3 genfscon fs194 / user0:object_r:type0:s3 genfscon fs195 / user0:object_r:type0:s3 genfscon fs196 / user0:object_r:type0:s3 genfscon fs197 / user0:object_r:type0:s3 genfscon fs198 / user0:object_r:type0:s3 genfscon fs199 / user0:object_r:type0:s3 genfscon fs200 / user0:object_r:type0:s3 genfscon fs201 / user0:object_r:type0:s3 genfscon fs202 / user0:object_r:type0:s3 genfscon fs203 / user0:object_r:type0:s3 genfscon fs204 / user0:object_r:type0:s3 genfscon fs205 / user0:object_r:type0:s3 genfscon fs206 / user0:object_r:type0:s3 genfscon fs207 / user0:object_r:type0:s3 genfscon fs208 / user0:object_r:type0:s3 genfscon fs209 / user0:object_r:type0:s3 genfscon fs210 / user0:object_r:type0:s3 genfscon fs211 / user0:object_r:type0:s3 genfscon fs212 / user0:object_r:type0:s3 genfscon fs213 / user0:object_r:type0:s3 genfscon fs214 / user0:object_r:type0:s3 genfscon fs215 / user0:object_r:type0:s3 genfscon fs216 / user0:object_r:type0:s3 genfscon fs217 / user0:object_r:type0:s3 genfscon fs218 / user0:object_r:type0:s3 genfscon fs219 / user0:object_r:type0:s3 genfscon fs220 / user0:object_r:type0:s3 genfscon fs221 / user0:object_r:type0:s3 genfscon fs222 / user0:object_r:type0:s3 genfscon fs223 / user0:object_r:type0:s3 genfscon fs224 / user0:object_r:type0:s3 genfscon fs225 / user0:object_r:type0:s3 genfscon fs226 / user0:object_r:type0:s3 genfscon fs227 / user0:object_r:type0:s3 genfscon fs228 / user0:object_r:type0:s3 genfscon fs229 / user0:object_r:type0:s3 genfscon fs230 / user0:object_r:type0:s3 genfscon fs231 / user0:object_r:type0:s3 genfscon fs232 / user0:object_r:type0:s3 genfscon fs233 / user0:object_r:type0:s3 genfscon fs234 / user0:object_r:type0:s3 genfscon fs235 / user0:object_r:type0:s3 genfscon fs236 / user0:object_r:type0:s3 genfscon fs237 / user0:object_r:type0:s3 genfscon fs238 / user0:object_r:type0:s3 genfscon fs239 / user0:object_r:type0:s3 genfscon fs240 / user0:object_r:type0:s3 genfscon fs241 / user0:object_r:type0:s3 genfscon fs242 / user0:object_r:type0:s3 genfscon fs243 / user0:object_r:type0:s3 genfscon fs244 / user0:object_r:type0:s3 genfscon fs245 / user0:object_r:type0:s3 genfscon fs246 / user0:object_r:type0:s3 genfscon fs247 / user0:object_r:type0:s3 genfscon fs248 / user0:object_r:type0:s3 genfscon fs249 / user0:object_r:type0:s3 genfscon fs250 / user0:object_r:type0:s3 genfscon fs251 / user0:object_r:type0:s3 genfscon fs252 / user0:object_r:type0:s3 genfscon fs253 / user0:object_r:type0:s3 genfscon fs254 / user0:object_r:type0:s3 genfscon fs255 / user0:object_r:type0:s3 genfscon fs256 / user0:object_r:type0:s3 genfscon fs257 / user0:object_r:type0:s3 genfscon fs258 / user0:object_r:type0:s3 genfscon fs259 / user0:object_r:type0:s3 genfscon fs260 / user0:object_r:type0:s3 genfscon fs261 / user0:object_r:type0:s3 genfscon fs262 / user0:object_r:type0:s3 genfscon fs263 / user0:object_r:type0:s3 genfscon fs264 / user0:object_r:type0:s3 genfscon fs265 / user0:object_r:type0:s3 genfscon fs266 / user0:object_r:type0:s3 genfscon fs267 / user0:object_r:type0:s3 genfscon fs268 / user0:object_r:type0:s3 genfscon fs269 / user0:object_r:type0:s3 genfscon fs270 / user0:object_r:type0:s3 genfscon fs271 / user0:object_r:type0:s3 genfscon fs272 / user0:object_r:type0:s3 genfscon fs273 / user0:object_r:type0:s3 genfscon fs274 / user0:object_r:type0:s3 genfscon fs275 / user0:object_r:type0:s3 genfscon fs276 / user0:object_r:type0:s3 genfscon fs277 / user0:object_r:type0:s3 genfscon fs278 / user0:object_r:type0:s3 genfscon fs279 / user0:object_r:type0:s3 genfscon fs280 / user0:object_r:type0:s3 genfscon fs281 / user0:object_r:type0:s3 genfscon fs282 / user0:object_r:type0:s3 genfscon fs283 / user0:object_r:type0:s3 genfscon fs284 / user0:object_r:type0:s3 genfscon fs285 / user0:object_r:type0:s3 genfscon fs286 / user0:object_r:type0:s3 genfscon fs287 / user0:object_r:type0:s3 genfscon fs288 / user0:object_r:type0:s3 genfscon fs289 / user0:object_r:type0:s3 genfscon fs290 / user0:object_r:type0:s3 genfscon fs291 / user0:object_r:type0:s3 genfscon fs292 / user0:object_r:type0:s3 genfscon fs293 / user0:object_r:type0:s3 genfscon fs294 / user0:object_r:type0:s3 genfscon fs295 / user0:object_r:type0:s3 genfscon fs296 / user0:object_r:type0:s3 genfscon fs297 / user0:object_r:type0:s3 genfscon fs298 / user0:object_r:type0:s3 genfscon fs299 / user0:object_r:type0:s3 #163 portcons portcon tcp 2 user0:object_r:type0:s4:c5 portcon tcp 4 user0:object_r:type0:s4:c5 portcon tcp 6 user0:object_r:type0:s4:c5 portcon tcp 8 user0:object_r:type0:s4:c5 portcon tcp 10 user0:object_r:type0:s4:c5 portcon tcp 12 user0:object_r:type0:s4:c5 portcon tcp 14 user0:object_r:type0:s4:c5 portcon tcp 16 user0:object_r:type0:s4:c5 portcon tcp 18 user0:object_r:type0:s4:c5 portcon tcp 20 user0:object_r:type0:s4:c5 portcon tcp 22 user0:object_r:type0:s4:c5 portcon tcp 24 user0:object_r:type0:s4:c5 portcon tcp 26 user0:object_r:type0:s4:c5 portcon tcp 28 user0:object_r:type0:s4:c5 portcon tcp 30 user0:object_r:type0:s4:c5 portcon tcp 32 user0:object_r:type0:s4:c5 portcon tcp 34 user0:object_r:type0:s4:c5 portcon tcp 36 user0:object_r:type0:s4:c5 portcon tcp 38 user0:object_r:type0:s4:c5 portcon tcp 40 user0:object_r:type0:s4:c5 portcon tcp 42 user0:object_r:type0:s4:c5 portcon tcp 44 user0:object_r:type0:s4:c5 portcon tcp 46 user0:object_r:type0:s4:c5 portcon tcp 48 user0:object_r:type0:s4:c5 portcon tcp 50 user0:object_r:type0:s4:c5 portcon tcp 52 user0:object_r:type0:s4:c5 portcon tcp 54 user0:object_r:type0:s4:c5 portcon tcp 56 user0:object_r:type0:s4:c5 portcon tcp 58 user0:object_r:type0:s4:c5 portcon tcp 60 user0:object_r:type0:s4:c5 portcon tcp 62 user0:object_r:type0:s4:c5 portcon tcp 64 user0:object_r:type0:s4:c5 portcon tcp 66 user0:object_r:type0:s4:c5 portcon tcp 68 user0:object_r:type0:s4:c5 portcon tcp 70 user0:object_r:type0:s4:c5 portcon tcp 72 user0:object_r:type0:s4:c5 portcon tcp 74 user0:object_r:type0:s4:c5 portcon tcp 76 user0:object_r:type0:s4:c5 portcon tcp 78 user0:object_r:type0:s4:c5 portcon tcp 80 user0:object_r:type0:s4:c5 portcon tcp 82 user0:object_r:type0:s4:c5 portcon tcp 84 user0:object_r:type0:s4:c5 portcon tcp 86 user0:object_r:type0:s4:c5 portcon tcp 88 user0:object_r:type0:s4:c5 portcon tcp 90 user0:object_r:type0:s4:c5 portcon tcp 92 user0:object_r:type0:s4:c5 portcon tcp 94 user0:object_r:type0:s4:c5 portcon tcp 96 user0:object_r:type0:s4:c5 portcon tcp 98 user0:object_r:type0:s4:c5 portcon tcp 100 user0:object_r:type0:s4:c5 portcon tcp 102 user0:object_r:type0:s4:c5 portcon tcp 104 user0:object_r:type0:s4:c5 portcon tcp 106 user0:object_r:type0:s4:c5 portcon tcp 108 user0:object_r:type0:s4:c5 portcon tcp 110 user0:object_r:type0:s4:c5 portcon tcp 112 user0:object_r:type0:s4:c5 portcon tcp 114 user0:object_r:type0:s4:c5 portcon tcp 116 user0:object_r:type0:s4:c5 portcon tcp 118 user0:object_r:type0:s4:c5 portcon tcp 120 user0:object_r:type0:s4:c5 portcon tcp 122 user0:object_r:type0:s4:c5 portcon tcp 124 user0:object_r:type0:s4:c5 portcon tcp 126 user0:object_r:type0:s4:c5 portcon tcp 128 user0:object_r:type0:s4:c5 portcon tcp 130 user0:object_r:type0:s4:c5 portcon tcp 132 user0:object_r:type0:s4:c5 portcon tcp 134 user0:object_r:type0:s4:c5 portcon tcp 136 user0:object_r:type0:s4:c5 portcon tcp 138 user0:object_r:type0:s4:c5 portcon tcp 140 user0:object_r:type0:s4:c5 portcon tcp 142 user0:object_r:type0:s4:c5 portcon tcp 144 user0:object_r:type0:s4:c5 portcon tcp 146 user0:object_r:type0:s4:c5 portcon tcp 148 user0:object_r:type0:s4:c5 portcon tcp 150 user0:object_r:type0:s4:c5 portcon tcp 152 user0:object_r:type0:s4:c5 portcon tcp 154 user0:object_r:type0:s4:c5 portcon tcp 156 user0:object_r:type0:s4:c5 portcon tcp 158 user0:object_r:type0:s4:c5 portcon tcp 160 user0:object_r:type0:s4:c5 portcon tcp 162 user0:object_r:type0:s4:c5 portcon tcp 164 user0:object_r:type0:s4:c5 portcon tcp 166 user0:object_r:type0:s4:c5 portcon tcp 168 user0:object_r:type0:s4:c5 portcon tcp 170 user0:object_r:type0:s4:c5 portcon tcp 172 user0:object_r:type0:s4:c5 portcon tcp 174 user0:object_r:type0:s4:c5 portcon tcp 176 user0:object_r:type0:s4:c5 portcon tcp 178 user0:object_r:type0:s4:c5 portcon tcp 180 user0:object_r:type0:s4:c5 portcon tcp 182 user0:object_r:type0:s4:c5 portcon tcp 184 user0:object_r:type0:s4:c5 portcon tcp 186 user0:object_r:type0:s4:c5 portcon tcp 188 user0:object_r:type0:s4:c5 portcon tcp 190 user0:object_r:type0:s4:c5 portcon tcp 192 user0:object_r:type0:s4:c5 portcon tcp 194 user0:object_r:type0:s4:c5 portcon tcp 196 user0:object_r:type0:s4:c5 portcon tcp 198 user0:object_r:type0:s4:c5 portcon tcp 200 user0:object_r:type0:s4:c5 portcon tcp 202 user0:object_r:type0:s4:c5 portcon tcp 204 user0:object_r:type0:s4:c5 portcon tcp 206 user0:object_r:type0:s4:c5 portcon tcp 208 user0:object_r:type0:s4:c5 portcon tcp 210 user0:object_r:type0:s4:c5 portcon tcp 212 user0:object_r:type0:s4:c5 portcon tcp 214 user0:object_r:type0:s4:c5 portcon tcp 216 user0:object_r:type0:s4:c5 portcon tcp 218 user0:object_r:type0:s4:c5 portcon tcp 220 user0:object_r:type0:s4:c5 portcon tcp 222 user0:object_r:type0:s4:c5 portcon tcp 224 user0:object_r:type0:s4:c5 portcon tcp 226 user0:object_r:type0:s4:c5 portcon tcp 228 user0:object_r:type0:s4:c5 portcon tcp 230 user0:object_r:type0:s4:c5 portcon tcp 232 user0:object_r:type0:s4:c5 portcon tcp 234 user0:object_r:type0:s4:c5 portcon tcp 236 user0:object_r:type0:s4:c5 portcon tcp 238 user0:object_r:type0:s4:c5 portcon tcp 240 user0:object_r:type0:s4:c5 portcon tcp 242 user0:object_r:type0:s4:c5 portcon tcp 244 user0:object_r:type0:s4:c5 portcon tcp 246 user0:object_r:type0:s4:c5 portcon tcp 248 user0:object_r:type0:s4:c5 portcon tcp 250 user0:object_r:type0:s4:c5 portcon tcp 252 user0:object_r:type0:s4:c5 portcon tcp 254 user0:object_r:type0:s4:c5 portcon tcp 256 user0:object_r:type0:s4:c5 portcon tcp 258 user0:object_r:type0:s4:c5 portcon tcp 260 user0:object_r:type0:s4:c5 portcon tcp 262 user0:object_r:type0:s4:c5 portcon tcp 264 user0:object_r:type0:s4:c5 portcon tcp 266 user0:object_r:type0:s4:c5 portcon tcp 268 user0:object_r:type0:s4:c5 portcon tcp 270 user0:object_r:type0:s4:c5 portcon tcp 272 user0:object_r:type0:s4:c5 portcon tcp 274 user0:object_r:type0:s4:c5 portcon tcp 276 user0:object_r:type0:s4:c5 portcon tcp 278 user0:object_r:type0:s4:c5 portcon tcp 280 user0:object_r:type0:s4:c5 portcon tcp 282 user0:object_r:type0:s4:c5 portcon tcp 284 user0:object_r:type0:s4:c5 portcon tcp 286 user0:object_r:type0:s4:c5 portcon tcp 288 user0:object_r:type0:s4:c5 portcon tcp 290 user0:object_r:type0:s4:c5 portcon tcp 292 user0:object_r:type0:s4:c5 portcon tcp 294 user0:object_r:type0:s4:c5 portcon tcp 296 user0:object_r:type0:s4:c5 portcon tcp 298 user0:object_r:type0:s4:c5 portcon tcp 300 user0:object_r:type0:s4:c5 portcon tcp 302 user0:object_r:type0:s4:c5 portcon tcp 304 user0:object_r:type0:s4:c5 portcon tcp 306 user0:object_r:type0:s4:c5 portcon tcp 308 user0:object_r:type0:s4:c5 portcon tcp 310 user0:object_r:type0:s4:c5 portcon tcp 312 user0:object_r:type0:s4:c5 portcon tcp 314 user0:object_r:type0:s4:c5 portcon tcp 316 user0:object_r:type0:s4:c5 portcon tcp 318 user0:object_r:type0:s4:c5 portcon tcp 320 user0:object_r:type0:s4:c5 portcon tcp 322 user0:object_r:type0:s4:c5 portcon tcp 324 user0:object_r:type0:s4:c5 portcon tcp 326 user0:object_r:type0:s4:c5 #167 netifcon netifcon eth0 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth1 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth2 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth3 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth4 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth5 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth6 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth7 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth8 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth9 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth10 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth11 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth12 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth13 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth14 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth15 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth16 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth17 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth18 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth19 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth20 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth21 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth22 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth23 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth24 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth25 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth26 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth27 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth28 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth29 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth30 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth31 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth32 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth33 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth34 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth35 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth36 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth37 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth38 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth39 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth40 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth41 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth42 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth43 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth44 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth45 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth46 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth47 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth48 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth49 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth50 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth51 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth52 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth53 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth54 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth55 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth56 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth57 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth58 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth59 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth60 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth61 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth62 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth63 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth64 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth65 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth66 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth67 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth68 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth69 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth70 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth71 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth72 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth73 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth74 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth75 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth76 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth77 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth78 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth79 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth80 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth81 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth82 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth83 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth84 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth85 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth86 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth87 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth88 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth89 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth90 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth91 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth92 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth93 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth94 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth95 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth96 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth97 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth98 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth99 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth100 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth101 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth102 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth103 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth104 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth105 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth106 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth107 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth108 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth109 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth110 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth111 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth112 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth113 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth114 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth115 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth116 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth117 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth118 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth119 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth120 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth121 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth122 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth123 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth124 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth125 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth126 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth127 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth128 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth129 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth130 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth131 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth132 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth133 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth134 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth135 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth136 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth137 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth138 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth139 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth140 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth141 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth142 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth143 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth144 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth145 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth146 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth147 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth148 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth149 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth150 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth151 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth152 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth153 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth154 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth155 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth156 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth157 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth158 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth159 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth160 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth161 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth162 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth163 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth164 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth165 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth166 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 # 173 nodecons nodecon 127.0.0.0 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.1 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.2 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.3 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.4 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.5 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.6 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.7 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.8 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.9 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.10 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.11 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.12 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.13 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.14 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.15 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.16 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.17 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.18 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.19 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.20 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.21 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.22 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.23 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.24 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.25 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.26 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.27 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.28 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.29 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.30 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.31 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.32 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.33 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.34 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.35 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.36 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.37 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.38 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.39 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.40 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.41 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.42 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.43 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.44 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.45 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.46 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.47 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.48 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.49 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.50 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.51 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.52 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.53 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.54 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.55 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.56 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.57 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.58 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.59 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.60 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.61 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.62 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.63 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.64 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.65 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.66 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.67 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.68 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.69 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.70 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.71 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.72 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.73 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.74 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.75 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.76 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.77 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.78 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.79 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.80 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.81 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.82 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.83 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.84 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.85 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.86 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.87 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.88 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.89 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.90 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.91 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.92 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.93 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.94 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.95 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.96 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.97 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.98 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.99 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.100 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.101 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.102 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.103 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.104 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.105 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.106 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.107 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.108 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.109 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.110 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.111 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.112 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.113 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.114 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.115 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.116 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.117 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.118 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.119 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.120 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.121 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.122 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.123 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.124 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.125 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.126 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.127 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.128 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.129 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.130 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.131 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.132 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.133 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.134 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.135 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.136 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.137 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.138 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.139 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.140 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.141 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.142 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.143 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.144 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.145 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.146 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.147 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.148 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.149 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.150 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.151 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.152 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.153 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.154 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.155 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.156 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.157 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.158 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.159 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.160 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.161 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.162 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.163 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.164 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.165 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.166 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.167 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.168 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.169 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.170 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.171 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.172 255.255.255.255 user0:object_r:type0:s4:c5 setools-4.1.1/tests/policyrep/selinuxpolicy.py000066400000000000000000000225271314142262400216450ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # from __future__ import print_function import copy import os import sys import subprocess import tempfile import unittest from setools import SELinuxPolicy, HandleUnknown from setools.policyrep.exception import InvalidPolicy class SELinuxPolicyTest(unittest.TestCase): @classmethod def setUpClass(cls): # create a temp file for the binary policy # and then have checkpolicy overwrite it. fd, cls.policy_path = tempfile.mkstemp() os.close(fd) try: command = [os.environ['CHECKPOLICY']] except KeyError: command = ["/usr/bin/checkpolicy"] command.extend(["-M", "-o", cls.policy_path, "-U", "reject", "tests/policyrep/selinuxpolicy.conf"]) with open(os.devnull, "w") as null: subprocess.check_call(command, stdout=null, shell=False, close_fds=True) try: cls.p = SELinuxPolicy("tests/policyrep/selinuxpolicy.conf") cls.p_binary = SELinuxPolicy(cls.policy_path) except: # This should never be hit, since this policy # successfully compiled with checkpolicy above. # If we do, clean up the binary policy since # tearDownClass() does not run. os.unlink(cls.policy_path) raise @classmethod def tearDownClass(cls): os.unlink(cls.policy_path) @unittest.skip("Retired for the SELinuxPolicyLoadError test suite.") def test_001_open_policy_error(self): """SELinuxPolicy: Invalid policy on open.""" self.assertRaises(InvalidPolicy, SELinuxPolicy, "tests/policyrep/selinuxpolicy-bad.conf") sys.stderr.write( "The \"category can not be associated\" error above is expected.") def test_002_open_policy_non_existant(self): """SELinuxPolicy: Non existant policy on open.""" self.assertRaises(OSError, SELinuxPolicy, "tests/policyrep/DOES_NOT_EXIST") def test_003_deepcopy(self): """SELinuxPolicy: Deep copy""" p = copy.deepcopy(self.p) self.assertIs(self.p.policy, p.policy) self.assertIs(self.p.filename, p.filename) def test_010_handle_unknown(self): """SELinuxPolicy: handle unknown setting.""" self.assertEqual(self.p_binary.handle_unknown, HandleUnknown.reject) def test_011_mls(self): """SELinuxPolicy: MLS status.""" self.assertTrue(self.p.mls) def test_012_version(self): """SELinuxPolicy: version.""" self.assertTrue(self.p.version) def test_100_allow_count(self): """SELinuxPolicy: allow count""" self.assertEqual(self.p.allow_count, 113) def test_101_auditallow_count(self): """SELinuxPolicy: auditallow count""" self.assertEqual(self.p.auditallow_count, 109) def test_102_boolean_count(self): """SELinuxPolicy: Boolean count.""" self.assertEqual(self.p.boolean_count, 127) # def test_103_bounds_count(self): def test_104_category_count(self): """SELinuxPolicy: category count""" self.assertEqual(self.p.category_count, 17) def test_105_class_count(self): """SELinuxPolicy: object class count""" self.assertEqual(self.p.class_count, 7) def test_106_common_count(self): """SELinuxPolicy: common permisison set count""" self.assertEqual(self.p.common_count, 3) def test_107_conditional_count(self): """SELinuxPolicy: conditional (expression) count""" self.assertEqual(self.p.conditional_count, 67) def test_108_constraint_count(self): """SELinuxPolicy: standard constraint count""" self.assertEqual(self.p.constraint_count, 19) # def test_109_default_count(self): def test_110_dontaudit_count(self): """SELinuxPolicy: dontaudit rule count""" self.assertEqual(self.p.dontaudit_count, 107) def test_111_fs_use_count(self): """SELinuxPolicy: fs_use_* count""" self.assertEqual(self.p.fs_use_count, 149) def test_112_genfscon_count(self): """SELinuxPolicy: genfscon count""" self.assertEqual(self.p.genfscon_count, 151) def test_113_initial_sid_count(self): """SELinuxPolicy: initial sid count""" self.assertEqual(self.p.initialsids_count, 11) def test_114_level_count(self): """SELinuxPolicy: MLS level count""" self.assertEqual(self.p.level_count, 13) def test_115_mls_constraint_count(self): """SELinuxPolicy: MLS constraint count""" self.assertEqual(self.p.mlsconstraint_count, 23) def test_116_mls_validatetrans_count(self): """SELinuxPolicy: MLS validatetrans count""" self.assertEqual(self.p.mlsvalidatetrans_count, 3) def test_117_netifcon_count(self): """SELinuxPolicy: netifcon count""" self.assertEqual(self.p.netifcon_count, 167) def test_118_neverallow_count(self): """SELinuxPolicy: neverallow rule count""" self.assertEqual(self.p.neverallow_count, 103) self.assertEqual(self.p_binary.neverallow_count, 0) def test_119_nodecon_count(self): """SELinuxPolicy: nodecon count""" self.assertEqual(self.p.nodecon_count, 173) def test_120_permission_count(self): """SELinuxPolicy: permission count""" self.assertEqual(self.p.permission_count, 29) def test_121_permissive_types_count(self): """SELinuxPolicy: permissive types count""" self.assertEqual(self.p.permissives_count, 73) def test_122_polcap_count(self): """SELinuxPolicy: policy capability count""" self.assertEqual(self.p.polcap_count, 2) def test_123_portcon_count(self): """SELinuxPolicy: portcon count""" self.assertEqual(self.p.portcon_count, 163) def test_124_range_transition_count(self): """SELinuxPolicy: range_transition count""" self.assertEqual(self.p.range_transition_count, 71) def test_125_role_count(self): """SELinuxPolicy: role count""" self.assertEqual(self.p.role_count, 131) # def test_126_role_attribute_count(self): def test_127_role_allow_count(self): """SELinuxPolicy: (role) allow count""" self.assertEqual(self.p.role_allow_count, 83) def test_128_role_transition_count(self): """SELinuxPolicy: role_transition count""" self.assertEqual(self.p.role_transition_count, 79) def test_129_type_count(self): """SELinuxPolicy: type count""" self.assertEqual(self.p.type_count, 137) def test_130_type_attribute_count(self): """SELinuxPolicy: type attribute count""" self.assertEqual(self.p.type_attribute_count, 157) def test_131_type_change_count(self): """SELinuxPolicy: type_change rule count""" self.assertEqual(self.p.type_change_count, 89) def test_132_type_member_count(self): """SELinuxPolicy: type_member rule count""" self.assertEqual(self.p.type_member_count, 61) def test_133_type_transition_count(self): """SELinuxPolicy: type_transition rule count""" self.assertEqual(self.p.type_transition_count, 97) def test_134_user_count(self): """SELinuxPolicy: user count""" self.assertEqual(self.p.user_count, 101) def test_135_validatetrans_count(self): """SELinuxPolicy: validatetrans count""" self.assertEqual(self.p.validatetrans_count, 5) def test_136_allowxperm_count(self): """SELinuxPolicy: allowxperm rount""" self.assertEqual(self.p.allowxperm_count, 179) def test_137_allowxperm_count(self): """SELinuxPolicy: auditallowxperm rount""" self.assertEqual(self.p.auditallowxperm_count, 181) def test_138_neverallowxperm_count(self): """SELinuxPolicy: neverallowxperm rount""" self.assertEqual(self.p.neverallowxperm_count, 191) def test_139_allowxperm_count(self): """SELinuxPolicy: dontauditxperm rount""" self.assertEqual(self.p.dontauditxperm_count, 193) class SELinuxPolicyLoadError(unittest.TestCase): """Test attempted loading of non-compiling policies.""" def _load_policy(self, policy): self.assertRaises(InvalidPolicy, SELinuxPolicy, "tests/policyrep/invalid_policies/"+policy) def test_nodecon_invalid_range(self): """SELinuxPolicy: invalid nodecon range (category not associated) error.""" self._load_policy("nodecon-invalid-range.conf") sys.stderr.write("The \"category can not be associated\" error above is expected.") # this is not fixed yet. See issue #72 @unittest.expectedFailure def test_user_level_not_in_range(self): """SELinuxPolicy: error for user's default level isn't within the range.""" self._load_policy("user-level-not-in-range.conf") setools-4.1.1/tests/policyrep/symbol.py000066400000000000000000000061311314142262400202340ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import copy import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.symbol import PolicySymbol class PolicySymbolTest(unittest.TestCase): """Tests for base symbol class methods.""" def mock_symbol_factory(self, name): """Factory function for Role objects, using a mock qpol object.""" mock_role = Mock(qpol.qpol_role_t) mock_role.name.return_value = name mock_role.this = name mock_policy = Mock(qpol.qpol_policy_t) return PolicySymbol(mock_policy, mock_role) def test_001_string(self): """Symbol: string representation""" sym = self.mock_symbol_factory("test1") self.assertEqual("test1", str(sym)) def test_010_hash(self): """Symbol: hash""" sym = self.mock_symbol_factory("test10") self.assertEqual(hash("test10"), hash(sym)) def test_020_eq(self): """Symbol: equality""" sym1 = self.mock_symbol_factory("test20") sym2 = self.mock_symbol_factory("test20") self.assertEqual(sym1, sym2) def test_021_eq(self): """Symbol: equality with string""" sym = self.mock_symbol_factory("test21") self.assertEqual("test21", sym) def test_030_ne(self): """Symbol: inequality""" sym1 = self.mock_symbol_factory("test30a") sym2 = self.mock_symbol_factory("test30b") self.assertNotEqual(sym1, sym2) def test_031_ne(self): """Symbol: inequality with string""" sym = self.mock_symbol_factory("test31a") self.assertNotEqual("test31b", sym) def test_040_lt(self): """Symbol: less-than""" sym1 = self.mock_symbol_factory("test40a") sym2 = self.mock_symbol_factory("test40b") self.assertTrue(sym1 < sym2) sym1 = self.mock_symbol_factory("test40") sym2 = self.mock_symbol_factory("test40") self.assertFalse(sym1 < sym2) sym1 = self.mock_symbol_factory("test40b") sym2 = self.mock_symbol_factory("test40a") self.assertFalse(sym1 < sym2) def test_050_deepcopy(self): """Symbol: deep copy""" sym1 = self.mock_symbol_factory("test50") sym2 = copy.deepcopy(sym1) self.assertIs(sym1.policy, sym2.policy) self.assertIs(sym1.qpol_symbol, sym2.qpol_symbol) setools-4.1.1/tests/policyrep/terule.py000066400000000000000000000407071314142262400202360ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import SELinuxPolicy from setools.policyrep.qpol import qpol_policy_t, qpol_avrule_t, qpol_terule_t, \ qpol_filename_trans_t from setools.policyrep.terule import te_rule_factory, validate_ruletype, TERuletype from setools.policyrep.exception import InvalidTERuleType, RuleNotConditional, RuleUseError, \ TERuleNoFilename @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class AVRuleTest(unittest.TestCase): def mock_avrule_factory(self, ruletype, source, target, tclass, perms, cond=None): mock_rule = Mock(qpol_avrule_t) mock_rule.is_extended.return_value = False mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.perm_iter = lambda x: iter(perms) if cond: mock_rule.cond.return_value = cond else: # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """AVRule factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """AVRule valid rule types.""" for r in ["allow", "neverallow", "auditallow", "dontaudit"]: self.assertEqual(r, validate_ruletype(r)) def test_002_validate_ruletype_invalid(self): """AVRule valid rule types.""" with self.assertRaises(InvalidTERuleType): self.assertTrue(validate_ruletype("role_transition")) def test_010_ruletype(self): """AVRule rule type""" rule = self.mock_avrule_factory("neverallow", "a", "b", "c", ['d']) self.assertEqual(TERuletype.neverallow, rule.ruletype) def test_020_source_type(self): """AVRule source type""" rule = self.mock_avrule_factory("allow", "source20", "b", "c", ['d']) self.assertEqual("source20", rule.source) def test_030_target_type(self): """AVRule target type""" rule = self.mock_avrule_factory("allow", "a", "target30", "c", ['d']) self.assertEqual("target30", rule.target) def test_040_object_class(self): """AVRule object class""" rule = self.mock_avrule_factory("allow", "a", "b", "class40", ['d']) self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """AVRule permissions""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['perm50a', 'perm50b']) self.assertSetEqual(set(['perm50a', 'perm50b']), rule.perms) def test_060_conditional(self): """AVRule conditional expression""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d'], cond="cond60") self.assertEqual("cond60", rule.conditional) def test_061_unconditional(self): """AVRule conditional expression (none)""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """AVRule default type""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleUseError): rule.default def test_080_filename(self): """AVRule filename (none)""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleUseError): rule.filename def test_100_statement_one_perm(self): """AVRule statement, one permission.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) self.assertEqual("allow a b:c d;", rule.statement()) def test_101_statement_two_perms(self): """AVRule statement, two permissions.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d1', 'd2']) # permissions are stored in a set, so the order may vary self.assertRegexpMatches(rule.statement(), "(" "allow a b:c { d1 d2 };" "|" "allow a b:c { d2 d1 };" ")") def test_102_statement_one_perm_cond(self): """AVRule statement, one permission, conditional.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d'], cond="cond102") self.assertEqual("allow a b:c d; [ cond102 ]:True", rule.statement()) def test_103_statement_two_perms_cond(self): """AVRule statement, two permissions, conditional.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d1', 'd2'], cond="cond103") # permissions are stored in a set, so the order may vary self.assertRegexpMatches(rule.statement(), "(" "allow a b:c { d1 d2 }; \[ cond103 ]" "|" "allow a b:c { d2 d1 }; \[ cond103 ]" ")") @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class AVRuleXpermTest(unittest.TestCase): def mock_avrule_factory(self, ruletype, source, target, tclass, xperm, perms): mock_rule = Mock(qpol_avrule_t) mock_rule.is_extended.return_value = True mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.xperm_type.return_value = xperm mock_rule.xperm_iter = lambda x: iter(perms) # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """AVRuleXperm factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """AVRuleXperm valid rule types.""" for r in ["allowxperm", "neverallowxperm", "auditallowxperm", "dontauditxperm"]: self.assertEqual(r, validate_ruletype(r)) def test_010_ruletype(self): """AVRuleXperm rule type""" rule = self.mock_avrule_factory("neverallowxperm", "a", "b", "c", "d", [0x0001]) self.assertEqual(TERuletype.neverallowxperm, rule.ruletype) def test_020_source_type(self): """AVRuleXperm source type""" rule = self.mock_avrule_factory("allowxperm", "source20", "b", "c", "d", [0x0001]) self.assertEqual("source20", rule.source) def test_030_target_type(self): """AVRuleXperm target type""" rule = self.mock_avrule_factory("allowxperm", "a", "target30", "c", "d", [0x0001]) self.assertEqual("target30", rule.target) def test_040_object_class(self): """AVRuleXperm object class""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "class40", "d", [0x0001]) self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """AVRuleXperm permissions""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0002, 0x0003]) self.assertSetEqual(set([0x0001, 0x0002, 0x0003]), rule.perms) def test_060_xperm_type(self): """AVRuleXperm xperm type""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "xperm60", [0x0001]) self.assertEqual("xperm60", rule.xperm_type) def test_070_unconditional(self): """AVRuleXperm conditional expression (none)""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleNotConditional): rule.conditional def test_080_default(self): """AVRuleXperm default type""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleUseError): rule.default def test_090_filename(self): """AVRuleXperm filename (none)""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleUseError): rule.filename def test_100_statement_one_perm(self): """AVRuleXperm statement, one permission.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) self.assertEqual("allowxperm a b:c d 0x0001;", rule.statement()) def test_101_statement_two_perms(self): """AVRuleXperm statement, two permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0003]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0001 0x0003 };") def test_102_statement_range_perms(self): """AVRuleXperm statement, range of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", list(range(0x0010, 0x0015))) self.assertEqual(rule.statement(), "allowxperm a b:c d 0x0010-0x0014;") def test_103_statement_single_perm_range_perms(self): """AVRuleXperm statement, single perm with range of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0003, 0x0004, 0x0005]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0001 0x0003-0x0005 };") def test_104_statement_two_range_perms(self): """AVRuleXperm statement, two ranges of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0003, 0x0004, 0x0005, 0x0007, 0x0008, 0x0009]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0003-0x0005 0x0007-0x0009 };") @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class TERuleTest(unittest.TestCase): def mock_terule_factory(self, ruletype, source, target, tclass, default, cond=None, filename=None): if filename: assert not cond mock_rule = Mock(qpol_filename_trans_t) mock_rule.filename.return_value = filename else: mock_rule = Mock(qpol_terule_t) if cond: mock_rule.cond.return_value = cond else: # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.default_type.return_value = default return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """TERule factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """TERule valid rule types.""" for r in ["type_transition", "type_change", "type_member"]: self.assertEqual(r, validate_ruletype(r)) @unittest.skip("TE ruletype changed to an enumeration.") def test_002_validate_ruletype_invalid(self): """TERule valid rule types.""" with self.assertRaises(InvalidTERuleType): self.assertTrue(validate_ruletype("role_transition")) def test_010_ruletype(self): """TERule rule type""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") self.assertEqual(TERuletype.type_transition, rule.ruletype) def test_020_source_type(self): """TERule source type""" rule = self.mock_terule_factory("type_transition", "source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """TERule target type""" rule = self.mock_terule_factory("type_transition", "a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """TERule object class""" rule = self.mock_terule_factory("type_transition", "a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """TERule permissions""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(RuleUseError): rule.perms def test_060_conditional(self): """TERule conditional expression""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", cond="cond60") self.assertEqual("cond60", rule.conditional) def test_061_unconditional(self): """TERule conditional expression (none)""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """TERule default type""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "default70") self.assertEqual("default70", rule.default) def test_080_filename(self): """TERule filename""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", filename="name80") self.assertEqual("name80", rule.filename) def test_081_filename_none(self): """TERule filename (none)""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(TERuleNoFilename): rule.filename def test_082_filename_wrong_ruletype(self): """TERule filename on wrong ruletype""" rule = self.mock_terule_factory("type_change", "a", "b", "c", "d") with self.assertRaises(RuleUseError): rule.filename def test_100_statement(self): """TERule statement.""" rule1 = self.mock_terule_factory("type_transition", "a", "b", "c", "d") rule2 = self.mock_terule_factory("type_change", "a", "b", "c", "d") self.assertEqual("type_transition a b:c d;", rule1.statement()) self.assertEqual("type_change a b:c d;", rule2.statement()) def test_102_statement_cond(self): """TERule statement, conditional.""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", cond="cond102") self.assertEqual("type_transition a b:c d; [ cond102 ]:True", rule.statement()) def test_103_statement_filename(self): """TERule statement, two permissions, conditional.""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", filename="name103") self.assertEqual("type_transition a b:c d \"name103\";", rule.statement()) setools-4.1.1/tests/policyrep/typeattr.conf000066400000000000000000000046321314142262400211040ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute attr1; attribute attr2; attribute attr3; type system alias sysalias; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; type everything alias { alias1 alias2 }, attr1, attr2; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/typeattr.py000066400000000000000000000262421314142262400206100ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import InvalidType, SymbolUseError from setools.policyrep.typeattr import type_factory, type_or_attr_factory, attribute_factory class TypeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") def mock_type_factory(self, name, attrs=[], alias=[], perm=False): """Factory function for Type objects, using a mock qpol object.""" mock_type = Mock(qpol.qpol_type_t) mock_type.name.return_value = name mock_type.type_iter.side_effect = AssertionError("Type iterator used") mock_type.attr_iter = lambda x: iter(attrs) mock_type.alias_iter = lambda x: iter(alias) mock_type.ispermissive.return_value = perm mock_type.isattr.return_value = False mock_type.isalias.return_value = False return type_factory(self.p.policy, mock_type) def test_001_lookup(self): """Type factory policy lookup.""" type_ = type_factory(self.p.policy, "system") self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Type factory policy invalid lookup.""" with self.assertRaises(InvalidType): type_factory(self.p.policy, "INVALID") def test_003_lookup_alias(self): """Type factory policy lookup alias.""" type_ = type_factory(self.p.policy, "sysalias", deref=True) self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_004_lookup_alias_no_deref(self): """Type factory policy lookup alias (no dereference).""" with self.assertRaises(TypeError): type_ = type_factory(self.p.policy, "sysalias") def test_005_lookup_attr(self): """Type factory policy lookup atribute.""" with self.assertRaises(TypeError): type_ = type_factory(self.p.policy, "attr1") def test_006_lookup2(self): """Type factory policy lookup (type_or_attr_factory).""" type_ = type_or_attr_factory(self.p.policy, "system") self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_007_lookup2_invalid(self): """Type factory policy invalid lookup (type_or_attr_factory).""" with self.assertRaises(InvalidType): type_or_attr_factory(self.p.policy, "INVALID") def test_008_lookup2_alias(self): """Type factory policy lookup alias (type_or_attr_factory).""" type_ = type_or_attr_factory(self.p.policy, "sysalias", deref=True) self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_009_lookup2_alias_no_deref(self): """Type factory policy lookup alias (no dereference, type_or_attr_factory).""" with self.assertRaises(TypeError): type_ = type_or_attr_factory(self.p.policy, "sysalias") def test_00a_lookup_object(self): """Type factory policy lookup of Type object.""" type1 = type_factory(self.p.policy, "system") type2 = type_factory(self.p.policy, type1) self.assertIs(type2, type1) def test_00b_lookup2_object(self): """Type factory policy lookup of Type object (type_or_attr_factory).""" type1 = type_or_attr_factory(self.p.policy, "system") type2 = type_or_attr_factory(self.p.policy, type1) self.assertIs(type2, type1) def test_010_string(self): """Type basic string rendering.""" type_ = self.mock_type_factory("name10") self.assertEqual("name10", str(type_)) def test_020_attrs(self): """Type attributes""" type_ = self.mock_type_factory("name20", attrs=['attr1', 'attr2', 'attr3']) self.assertEqual(['attr1', 'attr2', 'attr3'], sorted(type_.attributes())) def test_030_aliases(self): """Type aliases""" type_ = self.mock_type_factory("name30", alias=['alias1', 'alias2', 'alias3']) self.assertEqual(['alias1', 'alias2', 'alias3'], sorted(type_.aliases())) def test_040_expand(self): """Type expansion""" type_ = self.mock_type_factory("name40") expanded = list(type_.expand()) self.assertEqual(1, len(expanded)) self.assertIs(type_, expanded[0]) def test_050_permissive(self): """Type is permissive""" type_ = self.mock_type_factory("name50a") permtype = self.mock_type_factory("name50b", perm=True) self.assertFalse(type_.ispermissive) self.assertTrue(permtype.ispermissive) def test_060_statement(self): """Type basic statement""" type_ = self.mock_type_factory("name60") self.assertEqual("type name60;", type_.statement()) def test_061_statement_one_attr(self): """Type statement, one attribute""" type_ = self.mock_type_factory("name61", attrs=['attr1']) self.assertEqual("type name61, attr1;", type_.statement()) def test_062_statement_two_attr(self): """Type statement, two attributes""" type_ = self.mock_type_factory("name62", attrs=['attr1', 'attr2']) self.assertEqual("type name62, attr1, attr2;", type_.statement()) def test_063_statement_one_alias(self): """Type statement, one alias""" type_ = self.mock_type_factory("name63", alias=['alias1']) self.assertEqual("type name63 alias alias1;", type_.statement()) def test_064_statement_two_alias(self): """Type statement, two aliases""" type_ = self.mock_type_factory("name64", alias=['alias1', 'alias2']) self.assertEqual("type name64 alias { alias1 alias2 };", type_.statement()) def test_065_statement_one_attr_one_alias(self): """Type statement, one attribute, one alias""" type_ = self.mock_type_factory("name65", attrs=['attr1'], alias=['alias1']) self.assertEqual("type name65 alias alias1, attr1;", type_.statement()) def test_066_statement_two_attr_one_alias(self): """Type statement, two attributes, one alias""" type_ = self.mock_type_factory("name66", attrs=['attr1', 'attr2'], alias=['alias1']) self.assertEqual("type name66 alias alias1, attr1, attr2;", type_.statement()) def test_067_statement_one_attr_two_alias(self): """Type statement, one attribute, two aliases""" type_ = self.mock_type_factory("name67", attrs=['attr2'], alias=['alias3', 'alias4']) self.assertEqual("type name67 alias { alias3 alias4 }, attr2;", type_.statement()) def test_068_statement_two_attr_two_alias(self): """Type statement, two attributes, two aliases""" type_ = self.mock_type_factory("name68", attrs=['attr2', 'attr3'], alias=['alias2', 'alias4']) self.assertEqual("type name68 alias { alias2 alias4 }, attr2, attr3;", type_.statement()) class TypeAttributeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") def mock_attr_factory(self, name, types=[]): """Factory function for TypeAttribute objects, using a mock qpol object.""" mock_type = Mock(qpol.qpol_type_t) mock_type.name.return_value = name mock_type.type_iter = lambda x: iter(types) mock_type.attr_iter.side_effect = AssertionError("Attr iter used") mock_type.alias_iter.side_effect = AssertionError("Alias iter used") mock_type.ispermissive.side_effect = AssertionError("Permissive used") mock_type.isattr.return_value = True mock_type.isalias.side_effect = AssertionError("Alias used") return attribute_factory(self.p.policy, mock_type) def test_001_lookup(self): """TypeAttribute factory policy lookup.""" attr = attribute_factory(self.p.policy, "attr1") self.assertEqual("attr1", attr.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """TypeAttribute factory policy invalid lookup.""" with self.assertRaises(InvalidType): attribute_factory(self.p.policy, "INVALID") def test_006_lookup2(self): """TypeAttribute factory policy lookup (type_or_attr_factory).""" attr = type_or_attr_factory(self.p.policy, "attr1") self.assertEqual("attr1", attr.qpol_symbol.name(self.p.policy)) def test_007_lookup2_invalid(self): """TypeAttribute factory policy invalid lookup (type_or_attr_factory).""" with self.assertRaises(InvalidType): type_or_attr_factory(self.p.policy, "INVALID") def test_008_lookup_object(self): """TypeAttribute factory policy lookup of TypeAttribute object.""" attr1 = attribute_factory(self.p.policy, "attr1") attr2 = attribute_factory(self.p.policy, attr1) self.assertIs(attr2, attr1) def test_009_lookup2_object(self): """TypeAttribute factory policy lookup of TypeAttribute object (type_or_attr_factory).""" attr1 = type_or_attr_factory(self.p.policy, "attr2") attr2 = type_or_attr_factory(self.p.policy, attr1) self.assertIs(attr2, attr1) def test_010_string(self): """TypeAttribute basic string rendering.""" attr = self.mock_attr_factory("name10") self.assertEqual("name10", str(attr)) def test_020_attrs(self): """TypeAttribute attributes""" attr = self.mock_attr_factory("name20") with self.assertRaises(SymbolUseError): attr.attributes() def test_030_aliases(self): """TypeAttribute aliases""" attr = self.mock_attr_factory("name30") with self.assertRaises(SymbolUseError): attr.aliases() def test_040_expand(self): """TypeAttribute expansion""" attr = self.mock_attr_factory("name40", types=['type31a', 'type31b', 'type31c']) self.assertEqual(['type31a', 'type31b', 'type31c'], sorted(attr.expand())) def test_050_permissive(self): with self.assertRaises(SymbolUseError): attr = self.mock_attr_factory("name20") attr.ispermissive def test_060_statement(self): """TypeAttribute basic statement""" attr = self.mock_attr_factory("name60") self.assertEqual("attribute name60;", attr.statement()) def test_070_contains(self): """TypeAttribute: contains""" attr = self.mock_attr_factory("name70", types=['type31a', 'type31b', 'type31c']) self.assertIn("type31b", attr) self.assertNotIn("type30", attr) setools-4.1.1/tests/policyrep/user.conf000066400000000000000000000044401314142262400202030ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/policyrep/user.py000066400000000000000000000131511314142262400177050ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest try: from unittest.mock import Mock, patch except ImportError: from mock import Mock, patch from setools import SELinuxPolicy from setools.policyrep import qpol from setools.policyrep.exception import MLSDisabled, InvalidUser from setools.policyrep.user import user_factory class UserTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/user.conf") def mock_user_factory(self, name, roles, level=None, range_=None): """Factory function for User objects, using a mock qpol object.""" assert (level and range_) or (not level and not range_) # inject object_r, like the compiler does roles_with_objr = roles roles_with_objr.append('object_r') mock_user = Mock(qpol.qpol_user_t) mock_user.name.return_value = name mock_user.role_iter = lambda x: iter(roles_with_objr) mock_user.dfltlevel.return_value = level mock_user.range.return_value = range_ return user_factory(self.p.policy, mock_user) def test_001_lookup(self): """User factory policy lookup.""" user = user_factory(self.p.policy, "user10") self.assertEqual("user10", user.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """User factory policy invalid lookup.""" with self.assertRaises(InvalidUser): user_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """User factory policy lookup of User object.""" user1 = user_factory(self.p.policy, "user10") user2 = user_factory(self.p.policy, user1) self.assertIs(user2, user1) def test_010_string(self): """User basic string rendering.""" user = self.mock_user_factory("username", ['role1']) self.assertEqual("username", str(user)) def test_020_statement_role(self): """User statement, one role.""" with patch('setools.policyrep.mls.enabled', return_value=False): user = self.mock_user_factory("username", ['role20_r']) self.assertEqual("user username roles role20_r;", user.statement()) def test_021_statement_two_roles(self): """User statement, two roles.""" with patch('setools.policyrep.mls.enabled', return_value=False): user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) # roles are stored in a set, so the role order may vary self.assertRegexpMatches(user.statement(), "(" "user username roles { role20_r role21a_r };" "|" "user username roles { role21a_r role20_r };" ")") def test_022_statement_one_role_mls(self): """User statement, one role, MLS.""" user = self.mock_user_factory("username", ['role20_r'], level="s0", range_="s0-s2") self.assertEqual("user username roles role20_r level s0 range s0 - s2;", user.statement()) def test_023_statement_two_roles_mls(self): """User statement, two roles, MLS.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0 - s2") # roles are stored in a set, so the role order may vary self.assertRegexpMatches( user.statement(), "(" "user username roles { role20_r role21a_r } level s0 range s0 - s2;" "|" "user username roles { role21a_r role20_r } level s0 range s0 - s2;" ")") def test_030_roles(self): """User roles.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) self.assertSetEqual(user.roles, set(['role20_r', 'role21a_r'])) def test_040_level(self): """User level.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") self.assertEqual("s0", user.mls_level) def test_041_level_non_mls(self): """User level, MLS disabled.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) with patch('setools.policyrep.mls.enabled', return_value=False): with self.assertRaises(MLSDisabled): user.mls_level def test_050_range(self): """User level.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") self.assertEqual("s0 - s2", user.mls_range) def test_051_range_non_mls(self): """User level, MLS disabled.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") with patch('setools.policyrep.mls.enabled', return_value=False): with self.assertRaises(MLSDisabled): user.mls_range setools-4.1.1/tests/portconquery.conf000066400000000000000000000163441314142262400177770ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 # test 1: # protocol: UDP # ports: unset # user: unset # role: unset # type: unset # range: unset portcon udp 1 system:system:system:s0:c0.c1 # test 10: # protocol: unset # ports: unset # user: user10, exact # role: unset # type: unset # range: unset portcon tcp 10 user10:system:system:s0:c0.c1 # test 11: # protocol: unset # ports: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset portcon tcp 11 user11a:system:system:s0:c0.c1 portcon tcp 11000 user11b:system:system:s0:c0.c1 portcon tcp 11001 user11c:system:system:s0:c0.c1 # test 20: # protocol: unset # ports: unset # user: unset # role: role20_r, exact # type: unset # range: unset portcon tcp 20 system:role20_r:system:s0:c0.c1 # test 21: # protocol: unset # ports: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset portcon tcp 21 system:role21a_r:system:s0:c0.c1 portcon tcp 21000 system:role21b_r:system:s0:c0.c1 portcon tcp 21001 system:role21c_r:system:s0:c0.c1 # test 30: # protocol: unset # ports: unset # user: unset # role: unset # type: type30 # range: unset portcon tcp 30 system:system:type30:s0:c0.c1 # test 31: # protocol: unset # ports: unset # user: unset # role: unset # type: type31(b|c) # range: unset portcon tcp 31 system:system:type31a:s0:c0.c1 portcon tcp 31000 system:system:type31b:s0:c0.c1 portcon tcp 31001 system:system:type31c:s0:c0.c1 # test 40: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: equal portcon tcp 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: overlap portcon tcp 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: subset portcon tcp 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: superset portcon tcp 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: proper subset portcon tcp 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: proper superset portcon tcp 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # protocol: unset # ports: (50, 50) # user: unset # role: unset # type: unset # range: unset portcon tcp 50 system:system:system:s0:c0.c1 # test 51: # protocol: unset # ports: (50100, 50110) # user: unset # role: unset # type: unset # range: unset portcon tcp 50100-50110 system:system:system:s0:c0.c1 # test 52: # protocol: unset # ports: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50200 system:system:system:s0:c0.c1 # test 53: # protocol: unset # ports: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50300-50310 system:system:system:s0:c0.c1 # test 54: # protocol: unset # ports: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50400 system:system:system:s0:c0.c1 # test 55: # protocol: unset # ports: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50500-50510 system:system:system:s0:c0.c1 # test 56: # protocol: unset # ports: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50601 system:system:system:s0:c0.c1 # test 57: # protocol: unset # ports: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50700-50710 system:system:system:s0:c0.c1 # test 58: # protocol: unset # ports: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50801 system:system:system:s0:c0.c1 # test 59: # protocol: unset # ports: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50901-50910 system:system:system:s0:c0.c1 # test 60: # protocol: unset # ports: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60001 system:system:system:s0:c0.c1 # test 61: # protocol: unset # ports: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60101-60110 system:system:system:s0:c0.c1 # test 62: # protocol: unset # ports: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60200-60210 system:system:system:s0:c0.c1 # test 63: # protocol: unset # ports: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60300-60310 system:system:system:s0:c0.c1 # test 64: # protocol: unset # ports: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60400-60410 system:system:system:s0:c0.c1 # test 65: # protocol: unset # ports: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60501-60509 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.1.1/tests/portconquery.py000066400000000000000000000431311314142262400174740ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from socket import IPPROTO_UDP from setools import SELinuxPolicy, PortconQuery class PortconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/portconquery.conf") def test_000_unset(self): """Portcon query with no criteria""" # query with no parameters gets all ports. rules = sorted(self.p.portcons()) q = PortconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_protocol(self): """Portcon query with protocol match""" q = PortconQuery(self.p, protocol=IPPROTO_UDP) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(1, 1)], ports) def test_010_user_exact(self): """Portcon query with context user exact match""" q = PortconQuery(self.p, user="user10", user_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(10, 10)], ports) def test_011_user_regex(self): """Portcon query with context user regex match""" q = PortconQuery(self.p, user="user11(a|b)", user_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], ports) def test_020_role_exact(self): """Portcon query with context role exact match""" q = PortconQuery(self.p, role="role20_r", role_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(20, 20)], ports) def test_021_role_regex(self): """Portcon query with context role regex match""" q = PortconQuery(self.p, role="role21(a|c)_r", role_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], ports) def test_030_type_exact(self): """Portcon query with context type exact match""" q = PortconQuery(self.p, type_="type30", type_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(30, 30)], ports) def test_031_type_regex(self): """Portcon query with context type regex match""" q = PortconQuery(self.p, type_="type31(b|c)", type_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], ports) def test_040_range_exact(self): """Portcon query with context range exact match""" q = PortconQuery(self.p, range_="s0:c1 - s0:c0.c4") ports = sorted(p.ports for p in q.results()) self.assertListEqual([(40, 40)], ports) def test_041_range_overlap1(self): """Portcon query with context range overlap match (equal)""" q = PortconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap2(self): """Portcon query with context range overlap match (subset)""" q = PortconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap3(self): """Portcon query with context range overlap match (superset)""" q = PortconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap4(self): """Portcon query with context range overlap match (overlap low level)""" q = PortconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap5(self): """Portcon query with context range overlap match (overlap high level)""" q = PortconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_042_range_subset1(self): """Portcon query with context range subset match""" q = PortconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_042_range_subset2(self): """Portcon query with context range subset match (equal)""" q = PortconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_043_range_superset1(self): """Portcon query with context range superset match""" q = PortconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_043_range_superset2(self): """Portcon query with context range superset match (equal)""" q = PortconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_044_range_proper_subset1(self): """Portcon query with context range proper subset match""" q = PortconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset2(self): """Portcon query with context range proper subset match (equal)""" q = PortconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_044_range_proper_subset3(self): """Portcon query with context range proper subset match (equal low only)""" q = PortconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset4(self): """Portcon query with context range proper subset match (equal high only)""" q = PortconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_045_range_proper_superset1(self): """Portcon query with context range proper superset match""" q = PortconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset2(self): """Portcon query with context range proper superset match (equal)""" q = PortconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_045_range_proper_superset3(self): """Portcon query with context range proper superset match (equal low)""" q = PortconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset4(self): """Portcon query with context range proper superset match (equal high)""" q = PortconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_050_single_equal(self): """Portcon query with single port exact match""" q = PortconQuery(self.p, ports=(50, 50)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50, 50)], ports) def test_051_range_equal(self): """Portcon query with port range exact match""" q = PortconQuery(self.p, ports=(50100, 50110)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50100, 50110)], ports) def test_052_single_subset(self): """Portcon query with single port subset""" q = PortconQuery(self.p, ports=(50200, 50200), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50200, 50200)], ports) def test_053_range_subset(self): """Portcon query with range subset""" q = PortconQuery(self.p, ports=(50301, 50309), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_053_range_subset_edge1(self): """Portcon query with range subset, equal edge case""" q = PortconQuery(self.p, ports=(50300, 50310), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_054_single_proper_subset(self): """Portcon query with single port proper subset""" q = PortconQuery( self.p, ports=(50400, 50400), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset(self): """Portcon query with range proper subset""" q = PortconQuery( self.p, ports=(50501, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge1(self): """Portcon query with range proper subset, equal edge case""" q = PortconQuery( self.p, ports=(50500, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset_edge2(self): """Portcon query with range proper subset, low equal edge case""" q = PortconQuery( self.p, ports=(50500, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge3(self): """Portcon query with range proper subset, high equal edge case""" q = PortconQuery( self.p, ports=(50501, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_056_single_superset(self): """Portcon query with single port superset""" q = PortconQuery(self.p, ports=(50600, 50602), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_056_single_superset_edge1(self): """Portcon query with single port superset, equal edge case""" q = PortconQuery(self.p, ports=(50601, 50601), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_057_range_superset(self): """Portcon query with range superset""" q = PortconQuery(self.p, ports=(50700, 50711), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_057_range_superset_edge1(self): """Portcon query with range superset, equal edge case""" q = PortconQuery(self.p, ports=(50700, 50710), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_058_single_proper_superset(self): """Portcon query with single port proper superset""" q = PortconQuery( self.p, ports=(50800, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge1(self): """Portcon query with single port proper superset, equal edge case""" q = PortconQuery( self.p, ports=(50801, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_058_single_proper_superset_edge2(self): """Portcon query with single port proper superset, low equal edge case""" q = PortconQuery( self.p, ports=(50801, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge3(self): """Portcon query with single port proper superset, high equal edge case""" q = PortconQuery( self.p, ports=(50800, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_059_range_proper_superset(self): """Portcon query with range proper superset""" q = PortconQuery( self.p, ports=(50900, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge1(self): """Portcon query with range proper superset, equal edge case""" q = PortconQuery( self.p, ports=(50901, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_059_range_proper_superset_edge2(self): """Portcon query with range proper superset, equal high port edge case""" q = PortconQuery( self.p, ports=(50900, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge3(self): """Portcon query with range proper superset, equal low port edge case""" q = PortconQuery( self.p, ports=(50901, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_060_single_overlap(self): """Portcon query with single overlap""" q = PortconQuery(self.p, ports=(60001, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge1(self): """Portcon query with single overlap, range match low""" q = PortconQuery(self.p, ports=(60001, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge2(self): """Portcon query with single overlap, range match high""" q = PortconQuery(self.p, ports=(60000, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge3(self): """Portcon query with single overlap, range match proper superset""" q = PortconQuery(self.p, ports=(60000, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_061_range_overlap_low_half(self): """Portcon query with range overlap, low half match""" q = PortconQuery(self.p, ports=(60100, 60105), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60101, 60110)], ports) def test_062_range_overlap_high_half(self): """Portcon query with range overlap, high half match""" q = PortconQuery(self.p, ports=(60205, 60211), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60200, 60210)], ports) def test_063_range_overlap_middle(self): """Portcon query with range overlap, middle match""" q = PortconQuery(self.p, ports=(60305, 60308), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60300, 60310)], ports) def test_064_range_overlap_equal(self): """Portcon query with range overlap, equal match""" q = PortconQuery(self.p, ports=(60400, 60410), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60400, 60410)], ports) def test_065_range_overlap_superset(self): """Portcon query with range overlap, superset match""" q = PortconQuery(self.p, ports=(60500, 60510), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60501, 60509)], ports) setools-4.1.1/tests/rbacrulequery.conf000066400000000000000000000107411314142262400201050ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class process sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class process inherits infoflow { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # RBAC # test 1 # ruletype: unset # source: test1s, direct, no regex # target: unset # class: unset # default: unset role test1s; role test1t; allow test1s test1t; role_transition test1s system:infoflow test1t; # test 2 # ruletype: unset # source: test2s, direct, regex # target: unset # class: unset # default: unset role test2s1; role test2s2; role test2s3; role test2t; allow test2s1 test2t; role_transition test2s3 system:infoflow test2t; # test 10 # ruletype: unset # source: unset # target: test10t, direct, no regex # class: unset # default: unset role test10s; role test10t; allow test10s test10t; role_transition test10s system:infoflow test10t; # test 11 # ruletype: unset # source: unset # target: test11t(1|3), direct, regex # class: unset # default: unset role test11s; role test11t1; role test11t2; role test11t3; allow test11s test11t1; role_transition test11s system:infoflow test11t3; # test 12 # ruletype: unset # source: unset # target: test12t # class: unset # default: unset role test12s; type test12t; role test12d; allow test12s test12d; role_transition test12s test12t:infoflow test12d; # test 20 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # default: unset role test20; role test20d1; role test20d2; role_transition test20 system:infoflow test20d1; role_transition test20 system:infoflow2 test20d2; # test 21 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # default: unset role test21; role test21d1; role test21d2; role test21d3; role_transition test21 system:infoflow test21d1; role_transition test21 system:infoflow4 test21d2; role_transition test21 system:infoflow3 test21d3; # test 22 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # default: unset role test22; role test22d1; role test22d2; role test22d3; role_transition test22 system:infoflow test22d1; role_transition test22 system:infoflow5 test22d2; role_transition test22 system:infoflow6 test22d3; # test 30 # ruletype: unset # source: unset # target: unset # class: unset # default: test30d, no regex role test30s; role test30d; allow test30s test30d; role_transition test30s system:infoflow test30d; # test 31 # ruletype: unset # source: unset # target: unset # class: unset # default: test31d(2|3), regex role test31s; role test31d1; role test31d2; role test31d3; allow test31s test31d1; allow test31s test31d2; allow test31s test31d3; role_transition test31s system:infoflow test31d1; role_transition test31s system test31d2; role_transition test31s system:infoflow7 test31d3; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/rbacrulequery.py000066400000000000000000000141101314142262400176020ustar00rootroot00000000000000"""RBAC rule query unit tests.""" # Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # # pylint: disable=invalid-name,too-many-public-methods import unittest from setools import SELinuxPolicy, RBACRuleQuery from setools import RBACRuletype as RRT from setools.policyrep.exception import RuleUseError, RuleNotConditional from . import mixins class RBACRuleQueryTest(mixins.ValidateRule, unittest.TestCase): """RBAC rule query unit tests.""" @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/rbacrulequery.conf") def validate_allow(self, rule, source, target): """Validate a role allow rule.""" self.assertEqual(RRT.allow, rule.ruletype) self.assertEqual(source, rule.source) self.assertEqual(target, rule.target) self.assertRaises(RuleUseError, getattr, rule, "tclass") self.assertRaises(RuleUseError, getattr, rule, "default") self.assertRaises(RuleNotConditional, getattr, rule, "conditional") def test_000_unset(self): """RBAC rule query with no criteria.""" # query with no parameters gets all RBAC rules. rules = sorted(self.p.rbacrules()) q = RBACRuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """RBAC rule query with exact, direct, source match.""" q = RBACRuleQuery( self.p, source="test1s", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_allow(r[0], "test1s", "test1t") self.validate_rule(r[1], RRT.role_transition, "test1s", "system", "infoflow", "test1t") def test_002_source_direct_regex(self): """RBAC rule query with regex, direct, source match.""" q = RBACRuleQuery( self.p, source="test2s(1|2)", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test2s1", "test2t") def test_010_target_direct(self): """RBAC rule query with exact, direct, target match.""" q = RBACRuleQuery( self.p, target="test10t", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test10s", "test10t") def test_011_target_direct_regex(self): """RBAC rule query with regex, direct, target match.""" q = RBACRuleQuery( self.p, target="test11t(1|3)", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test11s", "test11t1") def test_012_target_type(self): """RBAC rule query with a type as target.""" q = RBACRuleQuery(self.p, target="test12t") r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test12s", "test12t", "infoflow", "test12d") @unittest.skip("Setting tclass to a string is no longer supported.") def test_020_class(self): """RBAC rule query with exact object class match.""" q = RBACRuleQuery(self.p, tclass="infoflow2", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test20", "system", "infoflow2", "test20d2") def test_021_class_list(self): """RBAC rule query with object class list match.""" q = RBACRuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test21", "system", "infoflow3", "test21d3") self.validate_rule(r[1], RRT.role_transition, "test21", "system", "infoflow4", "test21d2") def test_022_class_regex(self): """RBAC rule query with object class regex match.""" q = RBACRuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test22", "system", "infoflow5", "test22d2") self.validate_rule(r[1], RRT.role_transition, "test22", "system", "infoflow6", "test22d3") def test_030_default(self): """RBAC rule query with exact default match.""" q = RBACRuleQuery( self.p, default="test30d", default_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test30s", "system", "infoflow", "test30d") def test_031_default_regex(self): """RBAC rule query with regex default match.""" q = RBACRuleQuery( self.p, default="test31d(2|3)", default_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test31s", "system", "infoflow7", "test31d3") self.validate_rule(r[1], RRT.role_transition, "test31s", "system", "process", "test31d2") def test_040_ruletype(self): """RBAC rule query with rule type.""" q = RBACRuleQuery(self.p, ruletype=[RRT.allow]) num = 0 for num, r in enumerate(sorted(q.results()), start=1): self.assertEqual(r.ruletype, RRT.allow) # this will have to be updated as number of # role allows change in the test policy self.assertEqual(num, 9) setools-4.1.1/tests/rolequery.conf000066400000000000000000000067051314142262400172540ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Role Query # # test 1 # name: test1 # types: unset role test1; # test 2 # name: test2(a|b) regex # types: unset role test2a; role test2b; # test 10 # name: unset # types: test10a,test10b type test10a; type test10b; type test10c; role test10r1; role test10r2; role test10r3; role test10r4; role test10r5; role test10r6; role test10r7; role test10r1 types test10a; role test10r2 types { test10a test10b }; role test10r3 types { test10a test10b test10c }; role test10r4 types { test10b test10c }; role test10r5 types { test10a test10c }; role test10r6 types test10b; role test10r7 types test10c; # test 11 # name: unset # types: test11a,test11b equal type test11a; type test11b; type test11c; role test11r1; role test11r2; role test11r3; role test11r4; role test11r5; role test11r6; role test11r7; role test11r1 types test11a; role test11r2 types { test11a test11b }; role test11r3 types { test11a test11b test11c }; role test11r4 types { test11b test11c }; role test11r5 types { test11a test11c }; role test11r6 types test11b; role test11r7 types test11c; # test 12 # name: unset # types: test12(a|b) regex type test12a; type test12b; type test12c; role test12r1; role test12r2; role test12r3; role test12r4; role test12r5; role test12r6; role test12r7; role test12r1 types test12a; role test12r2 types { test12a test12b }; role test12r3 types { test12a test12b test12c }; role test12r4 types { test12b test12c }; role test12r5 types { test12a test12c }; role test12r6 types test12b; role test12r7 types test12c; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/rolequery.py000066400000000000000000000051021314142262400167450ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, RoleQuery class RoleQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/rolequery.conf") def test_000_unset(self): """Role query with no criteria.""" # query with no parameters gets all types. roles = sorted(self.p.roles()) q = RoleQuery(self.p) q_roles = sorted(q.results()) self.assertListEqual(roles, q_roles) def test_001_name_exact(self): """Role query with exact name match.""" q = RoleQuery(self.p, name="test1") roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test1"], roles) def test_002_name_regex(self): """Role query with regex name match.""" q = RoleQuery(self.p, name="test2(a|b)", name_regex=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test2a", "test2b"], roles) def test_010_type_intersect(self): """Role query with type set intersection.""" q = RoleQuery(self.p, types=["test10a", "test10b"]) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test10r1", "test10r2", "test10r3", "test10r4", "test10r5", "test10r6"], roles) def test_011_type_equality(self): """Role query with type set equality.""" q = RoleQuery(self.p, types=["test11a", "test11b"], types_equal=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test11r2"], roles) def test_012_type_regex(self): """Role query with type set match.""" q = RoleQuery(self.p, types="test12(a|b)", types_regex=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test12r1", "test12r2", "test12r3", "test12r4", "test12r5", "test12r6"], roles) setools-4.1.1/tests/sensitivityquery.conf000066400000000000000000000055541314142262400207060ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity sens; # test1 # name: test1 # alias: unset # sens: unset sensitivity test1; # test2 # name: test2(a|b) # alias: unset # sens: unset sensitivity test2a; sensitivity test2b; # test 10 # name: unset # alias: test10a # sens: unset sensitivity test10s1 alias { test10a test10c }; sensitivity test10s2 alias { test10b test10d }; # test 11 # name: unset # alias: test11(a|b) # sens: unset sensitivity test11s1 alias { test11a test11c }; sensitivity test11s2 alias { test11b test11d }; sensitivity test11s3 alias { test11e test11f }; # test 20 # name: unset # alias: unset # sens: test20 sensitivity test20; # test 21 # name: unset # alias: unset # sens: test21crit, dom sensitivity test21; sensitivity test21crit; # test 22 # name: unset # alias: unset # sens: test22crit, domby sensitivity test22; sensitivity test22crit; dominance { test21 test21crit test1 test2a test2b test10s1 sens test10s2 test11s1 test11s2 test11s3 test20 test22crit test22 } category begin; category end; #level decl level sens:begin.end; level test1; level test2a; level test2b; level test10s1; level test10s2; level test11s1; level test11s2; level test11s3; level test20; level test21; level test21crit; level test22; level test22crit; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ################################################################################ #users user system roles system level sens range sens - sens:begin.end; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:sens:begin sid security system:system:system:sens:begin #fs_use fs_use_trans devpts system:object_r:system:sens; fs_use_xattr ext3 system:object_r:system:sens; fs_use_task pipefs system:object_r:system:sens; #genfscon genfscon proc / system:object_r:system:sens genfscon proc /sys system:object_r:system:sens genfscon selinuxfs / system:object_r:system:sens:begin.end portcon tcp 80 system:object_r:system:sens netifcon eth0 system:object_r:system:sens system:object_r:system:sens nodecon 127.0.0.1 255.255.255.255 system:object_r:system:sens:begin nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:sens:begin setools-4.1.1/tests/sensitivityquery.py000066400000000000000000000070511314142262400204030ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, SensitivityQuery class SensitivityQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/sensitivityquery.conf") def test_000_unset(self): """Sensitivity query with no criteria.""" # query with no parameters gets all sensitivities. allsens = sorted(str(c) for c in self.p.sensitivities()) q = SensitivityQuery(self.p) qsens = sorted(str(c) for c in q.results()) self.assertListEqual(allsens, qsens) def test_001_name_exact(self): """Sensitivity query with exact name match.""" q = SensitivityQuery(self.p, name="test1") sens = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], sens) def test_002_name_regex(self): """Sensitivity query with regex name match.""" q = SensitivityQuery(self.p, name="test2(a|b)", name_regex=True) sens = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], sens) def test_010_alias_exact(self): """Sensitivity query with exact alias match.""" q = SensitivityQuery(self.p, alias="test10a") sens = sorted(str(t) for t in q.results()) self.assertListEqual(["test10s1"], sens) def test_011_alias_regex(self): """Sensitivity query with regex alias match.""" q = SensitivityQuery(self.p, alias="test11(a|b)", alias_regex=True) sens = sorted(str(t) for t in q.results()) self.assertListEqual(["test11s1", "test11s2"], sens) def test_020_sens_equal(self): """Sensitivity query with sens equality.""" q = SensitivityQuery(self.p, sens="test20") sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test20"], sens) def test_021_sens_dom1(self): """Sensitivity query with sens dominance.""" q = SensitivityQuery(self.p, sens="test21crit", sens_dom=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test21", "test21crit"], sens) def test_021_sens_dom2(self): """Sensitivity query with sens dominance (equal).""" q = SensitivityQuery(self.p, sens="test21", sens_dom=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], sens) def test_022_sens_domby1(self): """Sensitivity query with sens dominated-by.""" q = SensitivityQuery(self.p, sens="test22crit", sens_domby=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test22", "test22crit"], sens) def test_022_sens_domby2(self): """Sensitivity query with sens dominated-by (equal).""" q = SensitivityQuery(self.p, sens="test22", sens_domby=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], sens) setools-4.1.1/tests/terulequery.conf000066400000000000000000000212421314142262400176040ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # TE Rule Query # # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # perms: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; allow test1a test1t:infoflow hi_w; allow test1FAIL self:infoflow hi_w; # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # perms: unset attribute test2a; type test2s, test2a; type test2t; allow test2a test2t:infoflow hi_w; #allow test2s test2t:infoflow low_r; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # perms: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; allow test3s test3t:infoflow hi_w; allow test3aS test3t:infoflow low_r; allow test3b test3t:infoflow med_w; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # perms: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; allow test4a1 test4a1:infoflow hi_w; allow test4a2 test4a2:infoflow low_r; allow test4FAIL self:infoflow med_w; # test 5 # ruletype: unset # source: unset # target: test5a, direct, no regex # class: unset # perms: unset attribute test5a; type test5s; type test5t, test5a; allow test5s test5a:infoflow hi_w; allow test5s test5t:infoflow hi_w; # test 6 # ruletype: unset # source: unset # target: test6t, indirect, no regex # class: unset # perms: unset attribute test6a; type test6s; type test6t, test6a; allow test6s test6a:infoflow hi_w; allow test6s test6t:infoflow low_r; # test 7 # ruletype: unset # source: unset # target: test7a.*, direct, regex # class: unset # perms: unset attribute test7aPASS; attribute test7b; type test7s; type test7t, test7aPASS; type test7aFAIL, test7b; allow test7s test7t:infoflow hi_w; allow test7s test7aPASS:infoflow low_r; allow test7s test7b:infoflow med_w; # test 8 # ruletype: unset # source: unset # target: test8(s|t), indirect, regex # class: unset # perms: unset attribute test8a1; attribute test8a2; type test8s1, test8a1; type test8t1, test8a2; type test8FAIL; allow test8a1 test8a1:infoflow hi_w; allow test8a2 test8a2:infoflow low_r; allow test8FAIL self:infoflow med_w; # test 9 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # perms: unset type test9; allow test9 self:infoflow hi_w; allow test9 self:infoflow2 super_w; # test 10 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # perms: unset type test10; allow test10 self:infoflow hi_w; allow test10 self:infoflow4 hi_w; allow test10 self:infoflow3 null; # test 11 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # perms: unset type test11; allow test11 self:infoflow hi_w; allow test11 self:infoflow5 low_w; allow test11 self:infoflow6 med_r; # test 12 # ruletype: unset # source: unset # target: unset # class: unset # perms: super_r, any type test12a; type test12b; allow test12a self:infoflow7 super_r; allow test12b self:infoflow7 { super_r super_none }; # test 13 # ruletype: unset # source: unset # target: unset # class: unset # perms: super_w,super_none,super_both equal type test13a; type test13b; type test13c; type test13d; allow test13a self:infoflow7 super_w; allow test13b self:infoflow7 { super_w super_none }; allow test13c self:infoflow7 { super_w super_none super_both }; allow test13d self:infoflow7 { super_w super_none super_both super_unmapped }; # test 14 # ruletype: dontaudit,auditallow # source: unset # target: unset # class: unset # perms: unset type test14; auditallow test14 self:infoflow7 super_both; dontaudit test14 self:infoflow7 super_unmapped; # test 100 # ruletype: unset # source: unset # target: unset # class: unset # default: test100d type test100; type test100d; type_transition test100 test100:infoflow7 test100d; # test 101 # ruletype: unset # source: unset # target: unset # class: unset # default: test101. type test101; type test101d; type test101e; type_transition test101 test101d:infoflow7 test101e; type_transition test101 test101e:infoflow7 test101d; # test 200 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test200 type test200t1; type test200t2; bool test200 false; bool test200a true; if (test200) { allow test200t1 self:infoflow7 super_w; } if (test200 && test200a) { allow test200t2 self:infoflow7 super_w; } # test 201 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test201a test201b type test201t1; type test201t2; bool test201a false; bool test201b true; if (test201a) { allow test201t1 self:infoflow7 super_w; } if (test201b) { allow test201t2 self:infoflow7 super_w; } if (test201a && test201b) { allow test201t1 self:infoflow7 super_unmapped; } # test 202 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test202(a|b) type test202t1; type test202t2; bool test202a false; bool test202b true; bool test202c true; if (test202a) { allow test202t1 self:infoflow7 super_none; } if (test202c) { allow test202t2 self:infoflow7 super_both; } if (test202c || test202b) { allow test202t2 self:infoflow7 super_unmapped; } # test 300 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with source criteria that is an attribute, indirect match # # ruletype: unset # source: test300b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test300a; attribute test300b; type test300t1, test300a, test300b; type test300t2, test300b; type test300t3, test300a; type test300target; allow test300a test300target:infoflow7 hi_w; allow test300t1 self:infoflow7 hi_r; allow test300t2 self:infoflow7 med_w; allow test300b test300target:infoflow7 super_w; # test 301 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with target criteria that is an attribute, indirect match # # ruletype: unset # source: unset # target: test301b, indirect # class: unset # default: unset # boolean: unset attribute test301a; attribute test301b; type test301t1, test301a, test301b; type test301t2, test301b; type test301t3, test301a; type test301source; allow test301source test301a:infoflow7 hi_w; allow test301t1 self:infoflow7 hi_r; allow test301t2 self:infoflow7 med_w; allow test301source test301b:infoflow7 super_w; # test 302 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with default type criteria that is an attribute # # ruletype: unset # source: unset # target: unset # class: unset # default: test302b # boolean: unset attribute test302; type test302t1, test302; type test302t2, test302; type test302source; type_transition test302source test302t1:infoflow7 test302t1; type_transition test302source test302t2:infoflow7 test302t2; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/terulequery.py000066400000000000000000000503561314142262400173170ustar00rootroot00000000000000"""Type enforcement rule query unit tests.""" # Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # # pylint: disable=invalid-name,too-many-public-methods import unittest from setools import SELinuxPolicy, TERuleQuery from setools import TERuletype as TRT from . import mixins class TERuleQueryTest(mixins.ValidateRule, unittest.TestCase): """Type enforcement rule query unit tests.""" @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/terulequery.conf") def test_000_unset(self): """TE rule query with no criteria.""" # query with no parameters gets all TE rules. rules = sorted(self.p.terules()) q = TERuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """TE rule query with exact, direct, source match.""" q = TERuleQuery( self.p, source="test1a", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test1a", "test1t", "infoflow", set(["hi_w"])) def test_002_source_indirect(self): """TE rule query with exact, indirect, source match.""" q = TERuleQuery( self.p, source="test2s", source_indirect=True, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test2a", "test2t", "infoflow", set(["hi_w"])) def test_003_source_direct_regex(self): """TE rule query with regex, direct, source match.""" q = TERuleQuery( self.p, source="test3a.*", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test3aS", "test3t", "infoflow", set(["low_r"])) def test_004_source_indirect_regex(self): """TE rule query with regex, indirect, source match.""" q = TERuleQuery( self.p, source="test4(s|t)", source_indirect=True, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test4a1", "test4a1", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test4a2", "test4a2", "infoflow", set(["low_r"])) def test_005_target_direct(self): """TE rule query with exact, direct, target match.""" q = TERuleQuery( self.p, target="test5a", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test5s", "test5a", "infoflow", set(["hi_w"])) def test_006_target_indirect(self): """TE rule query with exact, indirect, target match.""" q = TERuleQuery( self.p, target="test6t", target_indirect=True, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test6s", "test6a", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test6s", "test6t", "infoflow", set(["low_r"])) def test_007_target_direct_regex(self): """TE rule query with regex, direct, target match.""" q = TERuleQuery( self.p, target="test7a.*", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test7s", "test7aPASS", "infoflow", set(["low_r"])) def test_008_target_indirect_regex(self): """TE rule query with regex, indirect, target match.""" q = TERuleQuery( self.p, target="test8(s|t)", target_indirect=True, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test8a1", "test8a1", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test8a2", "test8a2", "infoflow", set(["low_r"])) @unittest.skip("Setting tclass to a string is no longer supported.") def test_009_class(self): """TE rule query with exact object class match.""" q = TERuleQuery(self.p, tclass="infoflow2", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test9", "test9", "infoflow2", set(["super_w"])) def test_010_class_list(self): """TE rule query with object class list match.""" q = TERuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test10", "test10", "infoflow3", set(["null"])) self.validate_rule(r[1], TRT.allow, "test10", "test10", "infoflow4", set(["hi_w"])) def test_011_class_regex(self): """TE rule query with object class regex match.""" q = TERuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test11", "test11", "infoflow5", set(["low_w"])) self.validate_rule(r[1], TRT.allow, "test11", "test11", "infoflow6", set(["med_r"])) def test_012_perms_any(self): """TE rule query with permission set intersection.""" q = TERuleQuery(self.p, perms=["super_r"], perms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test12a", "test12a", "infoflow7", set(["super_r"])) self.validate_rule(r[1], TRT.allow, "test12b", "test12b", "infoflow7", set(["super_r", "super_none"])) def test_013_perms_equal(self): """TE rule query with permission set equality.""" q = TERuleQuery( self.p, perms=["super_w", "super_none", "super_both"], perms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test13c", "test13c", "infoflow7", set(["super_w", "super_none", "super_both"])) def test_014_ruletype(self): """TE rule query with rule type match.""" q = TERuleQuery(self.p, ruletype=["auditallow", "dontaudit"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.auditallow, "test14", "test14", "infoflow7", set(["super_both"])) self.validate_rule(r[1], TRT.dontaudit, "test14", "test14", "infoflow7", set(["super_unmapped"])) def test_052_perms_subset1(self): """TE rule query with permission subset.""" q = TERuleQuery(self.p, perms=["super_none", "super_both"], perms_subset=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test13c", "test13c", "infoflow7", set(["super_w", "super_none", "super_both"])) self.validate_rule(r[1], TRT.allow, "test13d", "test13d", "infoflow7", set(["super_w", "super_none", "super_both", "super_unmapped"])) def test_052_perms_subset2(self): """TE rule query with permission subset (equality).""" q = TERuleQuery(self.p, perms=["super_w", "super_none", "super_both", "super_unmapped"], perms_subset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test13d", "test13d", "infoflow7", set(["super_w", "super_none", "super_both", "super_unmapped"])) def test_100_default(self): """TE rule query with default type exact match.""" q = TERuleQuery(self.p, default="test100d", default_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.type_transition, "test100", "test100", "infoflow7", "test100d") def test_101_default_regex(self): """TE rule query with default type regex match.""" q = TERuleQuery(self.p, default="test101.", default_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.type_transition, "test101", "test101d", "infoflow7", "test101e") self.validate_rule(r[1], TRT.type_transition, "test101", "test101e", "infoflow7", "test101d") def test_200_boolean_intersection(self): """TE rule query with intersection Boolean set match.""" q = TERuleQuery(self.p, boolean=["test200"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test200t1", "test200t1", "infoflow7", set(["super_w"]), cond="test200") self.validate_rule(r[1], TRT.allow, "test200t2", "test200t2", "infoflow7", set(["super_w"]), cond="test200a && test200") def test_201_boolean_equal(self): """TE rule query with equal Boolean set match.""" q = TERuleQuery(self.p, boolean=["test201a", "test201b"], boolean_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test201t1", "test201t1", "infoflow7", set(["super_unmapped"]), cond="test201b && test201a") def test_202_boolean_regex(self): """TE rule query with regex Boolean match.""" q = TERuleQuery(self.p, boolean="test202(a|b)", boolean_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test202t1", "test202t1", "infoflow7", set(["super_none"]), cond="test202a") self.validate_rule(r[1], TRT.allow, "test202t2", "test202t2", "infoflow7", set(["super_unmapped"]), cond="test202b || test202c") def test_300_issue111(self): """TE rule query with attribute source criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, source="test300b", source_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allow, "test300a", "test300target", "infoflow7", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test300b", "test300target", "infoflow7", set(["super_w"])) self.validate_rule(r[2], TRT.allow, "test300t1", "test300t1", "infoflow7", set(["hi_r"])) self.validate_rule(r[3], TRT.allow, "test300t2", "test300t2", "infoflow7", set(["med_w"])) def test_301_issue111(self): """TE rule query with attribute target criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, target="test301b", target_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allow, "test301source", "test301a", "infoflow7", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test301source", "test301b", "infoflow7", set(["super_w"])) self.validate_rule(r[2], TRT.allow, "test301t1", "test301t1", "infoflow7", set(["hi_r"])) self.validate_rule(r[3], TRT.allow, "test301t2", "test301t2", "infoflow7", set(["med_w"])) def test_302_issue111(self): """TE rule query with attribute default type criteria.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, default="test302") r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.type_transition, "test302source", "test302t1", "infoflow7", "test302t1") self.validate_rule(r[1], TRT.type_transition, "test302source", "test302t2", "infoflow7", "test302t2") class TERuleQueryXperm(mixins.ValidateRule, unittest.TestCase): """TE Rule Query with extended permission rules.""" @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/terulequery2.conf") def test_001_source_direct(self): """Xperm rule query with exact, direct, source match.""" q = TERuleQuery( self.p, source="test1a", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test1a", "test1t", "infoflow", set(range(0xebe0, 0xebff+1)), xperm="ioctl") def test_002_source_indirect(self): """Xperm rule query with exact, indirect, source match.""" q = TERuleQuery( self.p, source="test2s", source_indirect=True, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test2a", "test2t", "infoflow", set([0x5411, 0x5451]), xperm="ioctl") def test_003_source_direct_regex(self): """Xperm rule query with regex, direct, source match.""" q = TERuleQuery( self.p, source="test3a.*", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test3aS", "test3t", "infoflow", set([0x1111]), xperm="ioctl") def test_004_source_indirect_regex(self): """Xperm rule query with regex, indirect, source match.""" q = TERuleQuery( self.p, source="test4(s|t)", source_indirect=True, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test4a1", "test4a1", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test4a2", "test4a2", "infoflow", set([0x1111]), xperm="ioctl") def test_005_target_direct(self): """Xperm rule query with exact, direct, target match.""" q = TERuleQuery( self.p, target="test5a", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test5s", "test5a", "infoflow", set([0x9999]), xperm="ioctl") def test_006_target_indirect(self): """Xperm rule query with exact, indirect, target match.""" q = TERuleQuery( self.p, target="test6t", target_indirect=True, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test6s", "test6a", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test6s", "test6t", "infoflow", set([0x1111]), xperm="ioctl") def test_007_target_direct_regex(self): """Xperm rule query with regex, direct, target match.""" q = TERuleQuery( self.p, target="test7a.*", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test7s", "test7aPASS", "infoflow", set([0x1111]), xperm="ioctl") def test_008_target_indirect_regex(self): """Xperm rule query with regex, indirect, target match.""" q = TERuleQuery( self.p, target="test8(s|t)", target_indirect=True, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test8a1", "test8a1", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test8a2", "test8a2", "infoflow", set([0x1111]), xperm="ioctl") def test_010_class_list(self): """Xperm rule query with object class list match.""" q = TERuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test10", "test10", "infoflow3", set([0]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test10", "test10", "infoflow4", set([0x9999]), xperm="ioctl") def test_011_class_regex(self): """Xperm rule query with object class regex match.""" q = TERuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test11", "test11", "infoflow5", set([0x1111]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test11", "test11", "infoflow6", set([0x5555]), xperm="ioctl") def test_014_ruletype(self): """Xperm rule query with rule type match.""" q = TERuleQuery(self.p, ruletype=["auditallowxperm", "dontauditxperm"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.auditallowxperm, "test14", "test14", "infoflow7", set([0x1234]), xperm="ioctl") self.validate_rule(r[1], TRT.dontauditxperm, "test14", "test14", "infoflow7", set([0x4321]), xperm="ioctl") def test_100_std_perm_any(self): """Xperm rule query match by standard permission.""" q = TERuleQuery(self.p, ruletype=["neverallow", "neverallowxperm"], perms=set(["ioctl", "hi_w"]), perms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.neverallow, "test100", "system", "infoflow2", set(["ioctl", "hi_w"])) self.validate_rule(r[1], TRT.neverallowxperm, "test100", "test100", "infoflow2", set([0x1234]), xperm="ioctl") def test_100_std_perm_equal(self): """Xperm rule query match by standard permission, equal perm set.""" q = TERuleQuery(self.p, ruletype=["neverallow", "neverallowxperm"], perms=set(["ioctl", "hi_w"]), perms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.neverallow, "test100", "system", "infoflow2", set(["ioctl", "hi_w"])) def test_101_xperm_any(self): """Xperm rule query match any perm set.""" q = TERuleQuery(self.p, xperms=[(0x9011, 0x9013)], xperms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allowxperm, "test101a", "test101a", "infoflow7", set([0x9011]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test101b", "test101b", "infoflow7", set([0x9011, 0x9012]), xperm="ioctl") self.validate_rule(r[2], TRT.allowxperm, "test101c", "test101c", "infoflow7", set([0x9011, 0x9012, 0x9013]), xperm="ioctl") self.validate_rule(r[3], TRT.allowxperm, "test101d", "test101d", "infoflow7", set([0x9011, 0x9012, 0x9013, 0x9014]), xperm="ioctl") def test_101_xperm_equal(self): """Xperm rule query match equal perm set.""" q = TERuleQuery(self.p, xperms=[(0x9011, 0x9013)], xperms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test101c", "test101c", "infoflow7", set([0x9011, 0x9012, 0x9013]), xperm="ioctl") setools-4.1.1/tests/terulequery2.conf000066400000000000000000000133151314142262400176700ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { ioctl } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; ######################################### # XPERM ioctl declarations and rules # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # perms: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; allowxperm test1a test1t:infoflow ioctl { 0xebe0-0xebff }; # sets AVRULE_XPERMS_IOCTLFUNCTION allowxperm test1FAIL self:infoflow ioctl { 0x8800-0x88ff }; # sets AVRULE_XPERMS_IOCTLDRIVER # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # perms: unset attribute test2a; type test2s, test2a; type test2t; allowxperm test2a test2t:infoflow ioctl { 0x5411 0x5451 }; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # perms: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; allowxperm test3s test3t:infoflow ioctl 0x9999; allowxperm test3aS test3t:infoflow ioctl 0x1111; allowxperm test3b test3t:infoflow ioctl 0x5555; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # perms: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; allowxperm test4a1 test4a1:infoflow ioctl 0x9999; allowxperm test4a2 test4a2:infoflow ioctl 0x1111; allowxperm test4FAIL self:infoflow ioctl 0x5555; # test 5 # ruletype: unset # source: unset # target: test5a, direct, no regex # class: unset # perms: unset attribute test5a; type test5s; type test5t, test5a; allowxperm test5s test5a:infoflow ioctl 0x9999; allowxperm test5s test5t:infoflow ioctl 0x9999; # test 6 # ruletype: unset # source: unset # target: test6t, indirect, no regex # class: unset # perms: unset attribute test6a; type test6s; type test6t, test6a; allowxperm test6s test6a:infoflow ioctl 0x9999; allowxperm test6s test6t:infoflow ioctl 0x1111; # test 7 # ruletype: unset # source: unset # target: test7a.*, direct, regex # class: unset # perms: unset attribute test7aPASS; attribute test7b; type test7s; type test7t, test7aPASS; type test7aFAIL, test7b; allowxperm test7s test7t:infoflow ioctl 0x9999; allowxperm test7s test7aPASS:infoflow ioctl 0x1111; allowxperm test7s test7b:infoflow ioctl 0x5555; # test 8 # ruletype: unset # source: unset # target: test8(s|t), indirect, regex # class: unset # perms: unset attribute test8a1; attribute test8a2; type test8s1, test8a1; type test8t1, test8a2; type test8FAIL; allowxperm test8a1 test8a1:infoflow ioctl 0x9999; allowxperm test8a2 test8a2:infoflow ioctl 0x1111; allowxperm test8FAIL self:infoflow ioctl 0x5555; # test 10 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # perms: unset type test10; allowxperm test10 self:infoflow ioctl 0x9999; allowxperm test10 self:infoflow4 ioctl 0x9999; allowxperm test10 self:infoflow3 ioctl 0x0; # test 11 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # perms: unset type test11; allowxperm test11 self:infoflow ioctl 0x9999; allowxperm test11 self:infoflow5 ioctl 0x1111; allowxperm test11 self:infoflow6 ioctl 0x5555; # test 14 # ruletype: dontauditxperm,auditallowxperm # source: unset # target: unset # class: unset # perms: unset type test14; auditallowxperm test14 self:infoflow7 ioctl 0x1234; dontauditxperm test14 self:infoflow7 ioctl 0x4321; # test 100 # ruletype: neverallow, neverallowxperm # source: unset # target: unset # class: unset # perms: ioctl (standard) type test100; neverallow test100 system:infoflow2 { ioctl hi_w }; neverallowxperm test100 self:infoflow2 ioctl 0x1234; # test 101 # ruletype: unset # source: unset # target: unset # class: unset # perms: 0x9011-0x9013 type test101a; type test101b; type test101c; type test101d; allowxperm test101a self:infoflow7 ioctl 0x9011; allowxperm test101b self:infoflow7 ioctl { 0x9011-0x9012 }; allowxperm test101c self:infoflow7 ioctl { 0x9011-0x9013 }; allowxperm test101d self:infoflow7 ioctl { 0x9011-0x9014 }; ############# END XPERM ############################ role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/typeattrquery.conf000066400000000000000000000060041314142262400201570ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Type Query # # test 1 # name: test1 # types: unset attribute test1; # test 2 # name: test2(a|b) regex # types: unset attribute test2a; attribute test2b; # test 10 # name: unset # types: attribute test10a; attribute test10b; attribute test10c; type test10t1, test10a; type test10t2, test10a, test10b; type test10t3, test10a, test10b, test10c; type test10t4, test10b, test10c; type test10t5, test10a, test10c; type test10t6, test10b; type test10t7, test10c; # test 11 # name: unset # types: attribute test11a; attribute test11b; attribute test11c; type test11t1, test11a; type test11t2, test11a, test11b; type test11t3, test11a, test11b, test11c; type test11t4, test11b, test11c; type test11t5, test11a, test11c; type test11t6, test11b; type test11t7, test11c; # test 12 # name: unset # types: attribute test12a; attribute test12b; attribute test12c; type test12t1, test12a; type test12t2, test12a, test12b; type test12t3, test12a, test12b, test12c; type test12t4, test12b, test12c; type test12t5, test12a, test12c; type test12t6, test12b; type test12t7, test12c; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/typeattrquery.py000066400000000000000000000052301314142262400176620ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, TypeAttributeQuery class TypeAttributeQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/typeattrquery.conf") def test_000_unset(self): """Type attribute query with no criteria.""" # query with no parameters gets all attrs. allattrs = sorted(self.p.typeattributes()) q = TypeAttributeQuery(self.p) qattrs = sorted(q.results()) self.assertListEqual(allattrs, qattrs) def test_001_name_exact(self): """Type attribute query with exact name match.""" q = TypeAttributeQuery(self.p, name="test1") attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test1"], attrs) def test_002_name_regex(self): """Type attribute query with regex name match.""" q = TypeAttributeQuery(self.p, name="test2(a|b)", name_regex=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test2a", "test2b"], attrs) def test_010_type_set_intersect(self): """Type attribute query with type set intersection.""" q = TypeAttributeQuery(self.p, types=["test10t1", "test10t7"]) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test10a", "test10c"], attrs) def test_011_type_set_equality(self): """Type attribute query with type set equality.""" q = TypeAttributeQuery(self.p, types=["test11t1", "test11t2", "test11t3", "test11t5"], types_equal=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test11a"], attrs) def test_012_type_set_regex(self): """Type attribute query with type set regex match.""" q = TypeAttributeQuery(self.p, types="test12t(1|2)", types_regex=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test12a", "test12b"], attrs) setools-4.1.1/tests/typequery.conf000066400000000000000000000070411314142262400172660ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Type Query # # test 1 # name: test1 # attrs: unset # alias: unset type test1; # test 2 # name: test2(a|b) regex # attrs: unset # alias: unset type test2a; type test2b; # test 10 # name: unset # attrs: test10a,test10b # alias: unset attribute test10a; attribute test10b; attribute test10c; type test10t1, test10a; type test10t2, test10a, test10b; type test10t3, test10a, test10b, test10c; type test10t4, test10b, test10c; type test10t5, test10a, test10c; type test10t6, test10b; type test10t7, test10c; # test 11 # name: unset # attrs: test11a,test11b equal # alias: unset attribute test11a; attribute test11b; attribute test11c; type test11t1, test11a; type test11t2, test11a, test11b; type test11t3, test11a, test11b, test11c; type test11t4, test11b, test11c; type test11t5, test11a, test11c; type test11t6, test11b; type test11t7, test11c; # test 12 # name: unset # attrs: test12(a|b) regex # alias: unset attribute test12a; attribute test12b; attribute test12c; type test12t1, test12a; type test12t2, test12a, test12b; type test12t3, test12a, test12b, test12c; type test12t4, test12b, test12c; type test12t5, test12a, test12c; type test12t6, test12b; type test12t7, test12c; # test 20 # name: unset # attrs: unset # alias: test20a type test20t1 alias { test20a test20c }; type test20t2 alias { test20b test20d }; # test 21 # name: unset # attrs: unset # alias: test21(a|b) type test21t1 alias { test21a test21c }; type test21t2 alias { test21b test21d }; type test21t3 alias { test21e test21f }; # test 30 # name: test30 # attrs: unset # alias: unset type test30; type test30a; permissive test30; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.1.1/tests/typequery.py000066400000000000000000000064751314142262400170030ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, TypeQuery class TypeQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/typequery.conf") def test_000_unset(self): """Type query with no criteria.""" # query with no parameters gets all types. alltypes = sorted(self.p.types()) q = TypeQuery(self.p) qtypes = sorted(q.results()) self.assertListEqual(alltypes, qtypes) def test_001_name_exact(self): """Type query with exact name match.""" q = TypeQuery(self.p, name="test1") types = sorted(str(t) for t in q.results()) self.assertListEqual(["test1"], types) def test_002_name_regex(self): """Type query with regex name match.""" q = TypeQuery(self.p, name="test2(a|b)", name_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test2a", "test2b"], types) def test_010_attr_intersect(self): """Type query with attribute set intersection.""" q = TypeQuery(self.p, attrs=["test10a", "test10b"]) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test10t1", "test10t2", "test10t3", "test10t4", "test10t5", "test10t6"], types) def test_011_attr_equality(self): """Type query with attribute set equality.""" q = TypeQuery(self.p, attrs=["test11a", "test11b"], attrs_equal=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test11t2"], types) def test_012_attr_regex(self): """Type query with attribute regex match.""" q = TypeQuery(self.p, attrs="test12(a|b)", attrs_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test12t1", "test12t2", "test12t3", "test12t4", "test12t5", "test12t6"], types) def test_020_alias_exact(self): """Type query with exact alias match.""" q = TypeQuery(self.p, alias="test20a") types = sorted(str(t) for t in q.results()) self.assertListEqual(["test20t1"], types) def test_021_alias_regex(self): """Type query with regex alias match.""" q = TypeQuery(self.p, alias="test21(a|b)", alias_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test21t1", "test21t2"], types) def test_030_permissive(self): """Type query with permissive match""" q = TypeQuery(self.p, permissive=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test30"], types) setools-4.1.1/tests/userquery.conf000066400000000000000000000127501314142262400172660ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; #level decl level s0:c0.c7; level s1:c0.c7; level s2:c0.c7; level s3:c0.c7; level s4:c0.c7; level s5:c0.c7; level s6:c0.c7; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # User Query # role test1_r; role test2a_r; role test2b_r; role test10a_r; role test10b_r; role test10c_r; role test11a_r; role test11b_r; role test11c_r; role test12a_r; role test12b_r; role test12c_r; # test 1 # name: test1_u # roles: unset user test1_u roles test1_r level s3:c5,c7 range s3:c5,c7; # test 2 # name: test2_u(1|2) regex # roles: unset user test2_u1 roles test2a_r level s3:c5,c7 range s3:c5,c7; user test2_u2 roles test2b_r level s3:c5,c7 range s3:c5,c7; # test 10 # name: unset # roles: test10a_r,test10b_r user test10_u1 roles test10a_r level s3:c5,c7 range s3:c5,c7; user test10_u2 roles { test10a_r test10b_r } level s3:c5,c7 range s3:c5,c7; user test10_u3 roles { test10a_r test10b_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u4 roles { test10b_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u5 roles { test10a_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u6 roles test10b_r level s3:c5,c7 range s3:c5,c7; user test10_u7 roles test10c_r level s3:c5,c7 range s3:c5,c7; # test 11 # name: unset # roles: test11a_r,test11b_r equal user test11_u1 roles test11a_r level s3:c5,c7 range s3:c5,c7; user test11_u2 roles { test11a_r test11b_r } level s3:c5,c7 range s3:c5,c7; user test11_u3 roles { test11a_r test11b_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u4 roles { test11b_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u5 roles { test11a_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u6 roles test11b_r level s3:c5,c7 range s3:c5,c7; user test11_u7 roles test11c_r level s3:c5,c7 range s3:c5,c7; # test 12 # name: unset # roles: test12(a|b)_r regex user test12_u1 roles test12a_r level s3:c5,c7 range s3:c5,c7; user test12_u2 roles { test12a_r test12b_r } level s3:c5,c7 range s3:c5,c7; user test12_u3 roles { test12a_r test12b_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u4 roles { test12b_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u5 roles { test12a_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u6 roles test12b_r level s3:c5,c7 range s3:c5,c7; user test12_u7 roles test12c_r level s3:c5,c7 range s3:c5,c7; # test 20 # name: unset # roles: unset # level: equal # range: unset user test20 roles system level s3:c0,c4 range s3 - s3:c0.c4,c7; # test 21 # name: unset # roles: unset # level: high, dom # range: unset user test21 roles system level s2:c1,c4 range s2 - s2:c0.c4,c7; # test 22 # name: unset # roles: unset # level: high, domby # range: unset user test22 roles system level s4:c2,c4 range s4 - s4:c0.c4,c7; # test 23 # name: unset # roles: unset # level: high, incomp # range: unset user test23 roles system level s3:c6 range s3 - s3:c0.c7; # test 40: # name: unset # roles: unset # level: unset # range: equal user test40 roles system level s0:c5 range s0:c5 - s0:c0.c5; # test 41: # name: unset # roles: unset # level: unset # range: overlap user test41 roles system level s1:c5 range s1:c5 - s1:c1.c3,c5; # test 42: # name: unset # roles: unset # level: unset # range: subset user test42 roles system level s2:c5 range s2:c5 - s2:c1.c3,c5; # test 43: # name: unset # roles: unset # level: unset # range: superset user test43 roles system level s3:c5 range s3:c5 - s3:c1.c3,c5,c6; # test 44: # name: unset # roles: unset # level: unset # range: proper subset user test44 roles system level s4:c5 range s4:c5 - s4:c1.c3,c5; # test 45: # name: unset # roles: unset # level: unset # range: proper superset user test45 roles system level s5:c5 range s5:c5 - s5:c1.c3,c5; ################################################################################ #users user system roles system level s0:c5 range s0:c5; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0:c5 sid security system:system:system:s0:c5 #fs_use fs_use_trans devpts system:object_r:system:s0:c5; fs_use_xattr ext3 system:object_r:system:s0:c5; fs_use_task pipefs system:object_r:system:s0:c5; #genfscon genfscon proc / system:object_r:system:s3 genfscon proc /sys system:object_r:system:s0:c5 genfscon selinuxfs / system:object_r:system:s3:c0.c4 portcon tcp 80 system:object_r:system:s0:c5 netifcon eth0 system:object_r:system:s0:c5 system:object_r:system:s0:c5 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0:c5 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0:c5 setools-4.1.1/tests/userquery.py000066400000000000000000000224001314142262400167620ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see . # import unittest from setools import SELinuxPolicy, UserQuery class UserQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/userquery.conf") def test_000_unset(self): """User query with no criteria.""" # query with no parameters gets all types. allusers = sorted(self.p.users()) q = UserQuery(self.p) qusers = sorted(q.results()) self.assertListEqual(allusers, qusers) def test_001_name_exact(self): """User query with exact name match.""" q = UserQuery(self.p, name="test1_u") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test1_u"], users) def test_002_name_regex(self): """User query with regex name match.""" q = UserQuery(self.p, name="test2_u(1|2)", name_regex=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test2_u1", "test2_u2"], users) def test_010_role_intersect(self): """User query with role set intersection.""" q = UserQuery(self.p, roles=["test10a_r", "test10b_r"]) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test10_u1", "test10_u2", "test10_u3", "test10_u4", "test10_u5", "test10_u6"], users) def test_011_role_equality(self): """User query with role set equality.""" q = UserQuery( self.p, roles=["test11a_r", "test11b_r"], roles_equal=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test11_u2"], users) def test_012_role_regex(self): """User query with role regex match.""" q = UserQuery(self.p, roles="test12(a|b)_r", roles_regex=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test12_u1", "test12_u2", "test12_u3", "test12_u4", "test12_u5", "test12_u6"], users) def test_020_level_equal(self): """User query with default level equality.""" q = UserQuery(self.p, level="s3:c0,c4") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test20"], users) def test_021_level_dom1(self): """User query with default level dominance.""" q = UserQuery(self.p, level="s2:c1,c2,c4", level_dom=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], users) def test_021_level_dom2(self): """User query with default level dominance (equal).""" q = UserQuery(self.p, level="s2:c1,c4", level_dom=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], users) def test_022_level_domby1(self): """User query with default level dominated-by.""" q = UserQuery(self.p, level="s3:c2", level_domby=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], users) def test_022_level_domby2(self): """User query with default level dominated-by (equal).""" q = UserQuery(self.p, level="s3:c2,c4", level_domby=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], users) def test_023_level_incomp(self): """User query with default level icomparable.""" q = UserQuery(self.p, level="s5:c0.c5,c7", level_incomp=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test23"], users) def test_040_range_exact(self): """User query with range exact match""" q = UserQuery(self.p, range_="s0:c5 - s0:c0.c5") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test40"], users) def test_041_range_overlap1(self): """User query with range overlap match (equal)""" q = UserQuery(self.p, range_="s1:c5 - s1:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap2(self): """User query with range overlap match (subset)""" q = UserQuery(self.p, range_="s1:c2,c5 - s1:c2.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap3(self): """User query with range overlap match (superset)""" q = UserQuery(self.p, range_="s1 - s1:c0.c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap4(self): """User query with range overlap match (overlap low level)""" q = UserQuery(self.p, range_="s1:c5 - s1:c2,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap5(self): """User query with range overlap match (overlap high level)""" q = UserQuery(self.p, range_="s1:c5,c2 - s1:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_042_range_subset1(self): """User query with range subset match""" q = UserQuery(self.p, range_="s2:c2,c5 - s2:c2.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test42"], users) def test_042_range_subset2(self): """User query with range subset match (equal)""" q = UserQuery(self.p, range_="s2:c5 - s2:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test42"], users) def test_043_range_superset1(self): """User query with range superset match""" q = UserQuery(self.p, range_="s3 - s3:c0.c6", range_superset=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test43"], users) def test_043_range_superset2(self): """User query with range superset match (equal)""" q = UserQuery(self.p, range_="s3:c5 - s3:c1.c3,c5.c6", range_superset=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test43"], users) def test_044_range_proper_subset1(self): """User query with range proper subset match""" q = UserQuery(self.p, range_="s4:c2,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_044_range_proper_subset2(self): """User query with range proper subset match (equal)""" q = UserQuery(self.p, range_="s4:c5 - s4:c1.c3,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual([], users) def test_044_range_proper_subset3(self): """User query with range proper subset match (equal low)""" q = UserQuery(self.p, range_="s4:c5 - s4:c1.c2,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_044_range_proper_subset4(self): """User query with range proper subset match (equal high)""" q = UserQuery(self.p, range_="s4:c1,c5 - s4:c1.c3,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_045_range_proper_superset1(self): """User query with range proper superset match""" q = UserQuery(self.p, range_="s5 - s5:c0.c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) def test_045_range_proper_superset2(self): """User query with range proper superset match (equal)""" q = UserQuery(self.p, range_="s5:c5 - s5:c1.c3,c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual([], users) def test_045_range_proper_superset3(self): """User query with range proper superset match (equal low)""" q = UserQuery(self.p, range_="s5:c5 - s5:c1.c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) def test_045_range_proper_superset4(self): """User query with range proper superset match (equal high)""" q = UserQuery(self.p, range_="s5 - s5:c1.c3,c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) setools-4.1.1/tox.ini000066400000000000000000000027101314142262400145170ustar00rootroot00000000000000[tox] minversion = 1.4 envlist = py27, py33, py34, py35 # Using site packages is not optimal, # but libselinux bindings are not # available via PyPI. # Any issues this hides should be found # by Travis CI, as that env is minimal. sitepackages = True [pep8] exclude = qpol.py max-line-length = 100 [testenv:pep8] deps = pep8 commands = pep8 --version pep8 setools/ setoolsgui/ tests/ seinfo seinfoflow sedta sesearch sediff --statistics [testenv:coverage] basepython = python3.3 deps = networkx==1.9 coverage enum34 commands = coverage --version coverage erase coverage run setup.py test coverage report [testenv:lint] basepython = python3.3 deps = pylint networkx==1.9 mock enum34 commands = {envpython} setup.py build_ext -i pylint --version pylint -E --rcfile .pylintrc setools tests seinfo seinfoflow sedta sesearch sediff # pylint can't see all members introduced by PyQt uic pylint -E --rcfile .pylintrc --disable=no-member,import-error setoolsgui [testenv] deps = networkx==1.9 py27: mock py27: enum34 py33: enum34 commands = {envpython} setup.py test recreate = True