Project import
diff --git a/selinux/Android.mk b/selinux/Android.mk new file mode 100644 index 0000000..4be2ae8 --- /dev/null +++ b/selinux/Android.mk
@@ -0,0 +1 @@ +include $(call all-named-subdir-makefiles, libsepol checkpolicy)
diff --git a/selinux/CleanSpec.mk b/selinux/CleanSpec.mk new file mode 100644 index 0000000..5658a40 --- /dev/null +++ b/selinux/CleanSpec.mk
@@ -0,0 +1,5 @@ +# This empty CleanSpec.mk file will prevent the build system +# from descending into subdirs. +# +$(call add-clean-step, rm -rf $(OUT_DIR)/host/linux-x86/bin/audit2allow) +$(call add-clean-step, rm -rf $(OUT_DIR)/host/linux-x86/bin/audit2why)
diff --git a/selinux/MODULE_LICENSE_GPL b/selinux/MODULE_LICENSE_GPL new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/selinux/MODULE_LICENSE_GPL
diff --git a/selinux/Makefile b/selinux/Makefile new file mode 100644 index 0000000..93e10de --- /dev/null +++ b/selinux/Makefile
@@ -0,0 +1,23 @@ +SUBDIRS=libsepol libselinux libsemanage sepolgen checkpolicy secilc policycoreutils # policy +PYSUBDIRS=libselinux libsemanage +DISTCLEANSUBIDRS=libselinux libsemanage + +ifeq ($(DEBUG),1) + export CFLAGS = -g3 -O0 -gdwarf-2 -fno-strict-aliasing -Wall -Wshadow -Werror + export LDFLAGS = -g +endif + +all install relabel clean test indent: + @for subdir in $(SUBDIRS); do \ + (cd $$subdir && $(MAKE) $@) || exit 1; \ + done + +install-pywrap install-rubywrap swigify: + @for subdir in $(PYSUBDIRS); do \ + (cd $$subdir && $(MAKE) $@) || exit 1; \ + done + +distclean: + @for subdir in $(DISTCLEANSUBDIRS); do \ + (cd $$subdir && $(MAKE) $@) || exit 1; \ + done
diff --git a/selinux/NOTICE b/selinux/NOTICE new file mode 100644 index 0000000..0b4d310 --- /dev/null +++ b/selinux/NOTICE
@@ -0,0 +1,2060 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. +All files are licensed under the FreeBSD license, excepet for thid party +components, which are subject to their respective licenses as specified in +their source files. + + FreeBSD License + +Copyright 2011 Tresys Technology, LLC. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of Tresys Technology, LLC. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License.
diff --git a/selinux/README b/selinux/README new file mode 100644 index 0000000..b58150b --- /dev/null +++ b/selinux/README
@@ -0,0 +1,19 @@ +Please submit all bug reports and patches to selinux@tycho.nsa.gov. +Subscribe via selinux-join@tycho.nsa.gov. + +Build dependencies on Fedora: +yum install audit-libs-devel bison bzip2-devel dbus-devel dbus-glib-devel flex flex-devel flex-static glib2-devel libcap-devel libcap-ng-devel pam-devel pcre-devel python-devel setools-devel swig ustr-devel xmlto redhat-rpm-config + +To build and install everything under a private directory, run: +make DESTDIR=~/obj install install-pywrap + +To install as the default system libraries and binaries +(overwriting any previously installed ones - dangerous!), +on x86_64, run: +make LIBDIR=/usr/lib64 SHLIBDIR=/lib64 install install-pywrap relabel +or on x86 (32-bit), run: +make install install-pywrap relabel + +This may render your system unusable if the upstream SELinux userspace +lacks library functions or other dependencies relied upon by your +distribution. If it breaks, you get to keep both pieces.
diff --git a/selinux/checkpolicy/Android.mk b/selinux/checkpolicy/Android.mk new file mode 100644 index 0000000..ee2f158 --- /dev/null +++ b/selinux/checkpolicy/Android.mk
@@ -0,0 +1,66 @@ +LOCAL_PATH:= $(call my-dir) + +common_src_files := \ + policy_parse.y \ + policy_scan.l \ + queue.c \ + module_compiler.c \ + parse_util.c \ + policy_define.c + +common_cflags := \ + -Wall -Wshadow -O2 \ + -pipe -fno-strict-aliasing \ + +common_includes := \ + $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/../libsepol/include/ \ + $(LOCAL_PATH)/../libsepol/src/ \ + +## +# checkpolicy +# +include $(CLEAR_VARS) + +LOCAL_MODULE := checkpolicy +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_SRC_FILES := $(common_src_files) checkpolicy.c +LOCAL_STATIC_LIBRARIES := libsepol +LOCAL_YACCFLAGS := -v +LOCAL_MODULE_CLASS := EXECUTABLES + +include $(BUILD_HOST_EXECUTABLE) + + +## +# checkmodule +# +include $(CLEAR_VARS) + +LOCAL_MODULE := checkmodule +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_SRC_FILES := $(common_src_files) checkmodule.c +LOCAL_STATIC_LIBRARIES := libsepol +LOCAL_YACCFLAGS := -v +LOCAL_MODULE_CLASS := EXECUTABLES + +include $(BUILD_HOST_EXECUTABLE) + +## +# dispol +# +include $(CLEAR_VARS) + +LOCAL_MODULE := dispol +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_SRC_FILES := test/dispol.c +LOCAL_STATIC_LIBRARIES := libsepol +LOCAL_MODULE_CLASS := EXECUTABLES + +include $(BUILD_HOST_EXECUTABLE)
diff --git a/selinux/checkpolicy/COPYING b/selinux/checkpolicy/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/selinux/checkpolicy/COPYING
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License.
diff --git a/selinux/checkpolicy/ChangeLog b/selinux/checkpolicy/ChangeLog new file mode 100644 index 0000000..429a163 --- /dev/null +++ b/selinux/checkpolicy/ChangeLog
@@ -0,0 +1,488 @@ + * Set flex as default lexer, from Julien Pivotto. + * Fix checkmodule output message, from Petr Lautrbach. + * Build policy on systems not supporting DCCP protocol, from Richard Haines. + * Fail if module name different than output base filename, from James Carter + * Add support for portcon dccp protocol, from Richard Haines + +2.5 2016-02-23 + * Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep. + * fix double free on name-based type transitions, from Stephen Smalley. + * switch operations to extended perms, from Jeff Vander Stoep. + * policy_define.c: fix compiler warnings, from Nick Kralevich. + * Remove uses of -Wno-return-type, from Dan Albert. + * Fix -Wreturn-type issues, from Dan Albert. + * dispol: display operations as ranges, from Jeff Vander Stoep. + * dispol: Extend to display operations, from Stephen Smalley. + * Add support for ioctl command whitelisting, from Jeff Vander Stoep. + * Add option to write CIL policy, from James Carter + * Add device tree ocontext nodes to Xen policy, from Daniel De Graaf. + * Widen Xen IOMEM context entries, from Daniel De Graaf. + * Expand allowed character set in paths, from Daniel De Graaf. + * Fix precedence between number and filesystem tokens, from Stephen Smalley. + * dispol/dismod fgets function warnings fix, from Emre Can Kucukoglu. + +2.4 2015-02-02 + * Fix bugs found by hardened gcc flags, from Nicolas Iooss. + * Add missing semicolon in cond_else parser rule, from Steven Capelli. + * Clear errno before call to strtol(3) from Dan Albert. + * Global C++11 compatibility from Dan Albert. + * Allow libsepol C++ static library on device from Daniel Cashman. + +2.3 2014-05-06 + * Add Android support for building dispol. + * Report source file and line information for neverallow failures. + * Prevent incompatible option combinations for checkmodule. + * Drop -lselinux from LDLIBS for test programs; not used. + * Add debug feature to display constraints/validatetrans from Richard Haines. + +2.2 2013-10-30 + * Fix hyphen usage in man pages from Laurent Bigonville. + * handle-unknown / -U required argument fix from Laurent Bigonville. + * Support overriding Makefile PATH and LIBDIR from Laurent Bigonville. + * Support space and : in filenames from Dan Walsh. + +2.1.12 2013-02-01 + * Fix errors found by coverity + * implement default type policy syntax + * Free allocated memory when clean up / exit. + +2.1.11 2012-09-13 + * fd leak reading policy + * check return code on ebitmap_set_bit + +2.1.10 2012-06-28 + * sepolgen: We need to support files that have a + in them + * Android/MacOS X build support + +2.1.9 2012-03-28 + * implement new default labeling behaviors for usr, role, range + * Fix dead links to www.nsa.gov/selinux + +2.1.8 2011-12-21 + * add new helper to translate class sets into bitmaps + +2.1.7 2011-12-05 + * dis* fixed signed vs unsigned errors + * dismod: fix unused parameter errors + * test: Makefile: include -W and -Werror + * allow ~ in filename transition rules + +2.1.6 2011-11-03 + * Revert "checkpolicy: Redo filename/filesystem syntax to support filename trans rules" + * drop libsepol dynamic link in checkpolicy + +2.1.5 2011-09-15 + * Separate tunable from boolean during compile. + +2.1.4 2011-08-26 + * checkpolicy: fix spacing in output message + +2.1.3 2011-08-17 + * add missing ; to attribute_role_def + *Redo filename/filesystem syntax to support filename trans + +2.1.2 2011-08-02 + * .gitignore changes + * dispol output of role trans + * man page update: build a module with an older policy version + +2.1.1 2011-08-01 + * Minor updates to filename trans rule output in dis{mod,pol} + +2.1.0 2011-07-27 + * Release, minor version bump + +2.0.27 2011-07-25 + * Add role attribute support by Harry Ciao + +2.0.26 2011-05-16 + * Wrap file names in filename transitions with quotes by Steve Lawrence. + * Allow filesystem names to start with a digit by James Carter. + +2.0.25 2011-05-02 + * Add support for using the last path compnent in type transitions by Eric + Paris. + * Allow single digit module versions by Daniel Walsh. + * Use better filename identifier for filenames by Daniel Walsh. + * Use #defines for dismod selections by Eric Paris. + +2.0.24 2011-04-11 + * Add new class field in role_transition by Harry Ciao. + +2.0.23 2010-12-16 + * Remove unused variables to fix compliation under GCC 4.6 by Justin Mattock + +2.0.22 2010-06-14 + * Update checkmodule man page and usage by Daniel Walsh and Steve Lawrence + +2.0.21 2009-11-27 + * Add long options to checkpolicy and checkmodule by Guido + Trentalancia <guido@trentalancia.com> + +2.0.20 2009-10-14 + * Add support for building Xen policies from Paul Nuzzi. + +2.0.19 2009-02-18 + * Fix alias field in module format, caused by boundary format change + from Caleb Case. + +2.0.18 2008-10-14 + * Properly escape regex symbols in the lexer from Stephen Smalley. + +2.0.17 2008-10-09 + * Add bounds support from KaiGai Kohei. + +2.0.16 2008-05-27 + * Update checkpolicy for user and role mapping support from Joshua Brindle. + +2.0.15 2008-05-05 + * Fix for policy module versions that look like IPv4 addresses from Jim Carter. + Resolves bug 444451. + +2.0.14 2008-03-24 + * Add permissive domain support from Eric Paris. + +2.0.13 2008-03-05 + * Split out non-grammar parts of policy_parse.yacc into + policy_define.c and policy_define.h from Todd C. Miller. + +2.0.12 2008-03-04 + * Initialize struct policy_file before using it, from Todd C. Miller. + +2.0.11 2008-03-03 + * Remove unused define, move variable out of .y file, simplify COND_ERR, from Todd C. Miller. + +2.0.10 2008-02-28 + * Use yyerror2() where appropriate from Todd C. Miller. + +2.0.9 2008-02-04 + * Update dispol for libsepol avtab changes from Stephen Smalley. + +2.0.8 2008-01-24 + * Deprecate role dominance in parser. + +2.0.7 2008-01-02 + * Added support for policy capabilities from Todd Miller. + +2.0.6 2007-11-15 + * Initialize the source file name from the command line argument so that checkpolicy/checkmodule report something more useful than "unknown source". + +2.0.5 2007-11-01 + * Merged remove use of REJECT and trailing context in lex rules; make ipv4 address parsing like ipv6 from James Carter. + +2.0.4 2007-09-18 + * Merged handle unknown policydb flag support from Eric Paris. + Adds new command line options -U {allow, reject, deny} for selecting + the flag when a base module or kernel policy is built. + +2.0.3 2007-05-31 + * Merged fix for segfault on duplicate require of sensitivity from Caleb Case. + * Merged fix for dead URLs in checkpolicy man pages from Dan Walsh. + +2.0.2 2007-04-12 + * Merged checkmodule man page fix from Dan Walsh. + +2.0.1 2007-02-20 + * Merged patch to allow dots in class identifiers from Caleb Case. + +2.0.0 2007-02-01 + * Merged patch to use new libsepol error codes by Karl MacMillan. + +1.34.0 2007-01-18 + * Updated version for stable branch. + +1.33.1 2006-11-13 + * Collapse user identifiers and identifiers together. + +1.32 2006-10-17 + * Updated version for release. + +1.30.12 2006-09-28 + * Merged user and range_transition support for modules from + Darrel Goeddel + +1.30.11 2006-09-05 + * merged range_transition enhancements and user module format + changes from Darrel Goeddel + +1.30.10 2006-08-03 + * Merged symtab datum patch from Karl MacMillan. + +1.30.9 2006-06-29 + * Lindent. + +1.30.8 2006-06-29 + * Merged patch to remove TE rule conflict checking from the parser + from Joshua Brindle. This can only be done properly by the + expander. + +1.30.7 2006-06-27 + * Merged patch to make checkpolicy/checkmodule handling of + duplicate/conflicting TE rules the same as the expander + from Joshua Brindle. + +1.30.6 2006-06-26 + * Merged optionals in base take 2 patch set from Joshua Brindle. + +1.30.5 2006-05-05 + * Merged compiler cleanup patch from Karl MacMillan. + * Merged fix warnings patch from Karl MacMillan. + +1.30.4 2006-04-05 + * Changed require_class to reject permissions that have not been + declared if building a base module. + +1.30.3 2006-03-28 + * Fixed checkmodule to call link_modules prior to expand_module + to handle optionals. + +1.30.2 2006-03-28 + * Fixed require_class to avoid shadowing permissions already defined + in an inherited common definition. + +1.30.1 2006-03-22 + * Moved processing of role and user require statements to 2nd pass. + +1.30 2006-03-14 + * Updated version for release. + +1.29.5 2006-03-09 + * Fixed bug in role dominance (define_role_dom). + +1.29.4 2006-02-14 + * Added a check for failure to declare each sensitivity in + a level definition. + +1.29.3 2006-02-13 + * Changed to clone level data for aliased sensitivities to + avoid double free upon sens_destroy. Bug reported by Kevin + Carr of Tresys Technology. + +1.29.2 2006-02-13 + * Merged optionals in base patch from Joshua Brindle. + +1.29.1 2006-02-01 + * Merged sepol_av_to_string patch from Joshua Brindle. + +1.28 2005-12-07 + * Updated version for release. + +1.27.20 2005-12-02 + * Merged checkmodule man page from Dan Walsh, and edited it. + +1.27.19 2005-12-01 + * Added error checking of all ebitmap_set_bit calls for out of + memory conditions. + +1.27.18 2005-12-01 + * Merged removal of compatibility handling of netlink classes + (requirement that policies with newer versions include the + netlink class definitions, remapping of fine-grained netlink + classes in newer source policies to single netlink class when + generating older policies) from George Coker. + +1.27.17 2005-10-25 + * Merged dismod fix from Joshua Brindle. + +1.27.16 2005-10-20 + * Removed obsolete cond_check_type_rules() function and call and + cond_optimize_lists() call from checkpolicy.c; these are handled + during parsing and expansion now. + +1.27.15 2005-10-19 + * Updated calls to expand_module for interface change. + +1.27.14 2005-10-19 + * Changed checkmodule to verify that expand_module succeeds + when building base modules. + +1.27.13 2005-10-19 + * Merged module compiler fixes from Joshua Brindle. + +1.27.12 2005-10-19 + * Removed direct calls to hierarchy_check_constraints() and + check_assertions() from checkpolicy since they are now called + internally by expand_module(). + +1.27.11 2005-10-18 + * Updated for changes to sepol policydb_index_others interface. + +1.27.10 2005-10-17 + * Updated for changes to sepol expand_module and link_modules interfaces. + +1.27.9 2005-10-13 + * Merged support for require blocks inside conditionals from + Joshua Brindle (Tresys). + +1.27.8 2005-10-06 + * Updated for changes to libsepol. + +1.27.7 2005-10-05 + * Merged several bug fixes from Joshua Brindle (Tresys). + +1.27.6 2005-10-03 + * Merged MLS in modules patch from Joshua Brindle (Tresys). + +1.27.5 2005-09-28 + * Merged error handling improvement in checkmodule from Karl MacMillan (Tresys). + +1.27.4 2005-09-26 + * Merged bugfix for dup role transition error messages from + Karl MacMillan (Tresys). + +1.27.3 2005-09-23 + * Merged policyver/modulever patches from Joshua Brindle (Tresys). + +1.27.2 2005-09-20 + * Fixed parse_categories handling of undefined category. + +1.27.1 2005-09-16 + * Merged bug fix for role dominance handling from Darrel Goeddel (TCS). + +1.26 2005-09-06 + * Updated version for release. + +1.25.12 2005-08-22 + * Fixed handling of validatetrans constraint expressions. + Bug reported by Dan Walsh for checkpolicy -M. + +1.25.11 2005-08-18 + * Merged use-after-free fix from Serge Hallyn (IBM). + Bug found by Coverity. + +1.25.10 2005-08-15 + * Fixed further memory leaks found by valgrind. + +1.25.9 2005-08-15 + * Changed checkpolicy to destroy the policydbs prior to exit + to allow leak detection. + * Fixed several memory leaks found by valgrind. + +1.25.8 2005-08-11 + * Updated checkpolicy and dispol for the new avtab format. + Converted users of ebitmaps to new inline operators. + Note: The binary policy format version has been incremented to + version 20 as a result of these changes. To build a policy + for a kernel that does not yet include these changes, use + the -c 19 option to checkpolicy. + +1.25.7 2005-08-11 + * Merged patch to prohibit use of "self" as a type name from Jason Tang (Tresys). + +1.25.6 2005-08-10 + * Merged patch to fix dismod compilation from Joshua Brindle (Tresys). + +1.25.5 2005-08-09 + * Fixed call to hierarchy checking code to pass the right policydb. + +1.25.4 2005-08-02 + * Merged patch to update dismod for the relocation of the + module read/write code from libsemanage to libsepol, and + to enable build of test subdirectory from Jason Tang (Tresys). + +1.25.3 2005-07-18 + * Merged hierarchy check fix from Joshua Brindle (Tresys). + +1.25.2 2005-07-06 + * Merged loadable module support from Tresys Technology. + +1.25.1 2005-06-24 + * Merged patch to prohibit the use of * and ~ in type sets + (other than in neverallow statements) and in role sets + from Joshua Brindle (Tresys). + +1.24 2005-06-20 + * Updated version for release. + +1.23.4 2005-05-19 + * Merged cleanup patch from Dan Walsh. + +1.23.3 2005-05-13 + * Added sepol_ prefix to Flask types to avoid namespace + collision with libselinux. + +1.23.2 2005-04-29 + * Merged identifier fix from Joshua Brindle (Tresys). + +1.23.1 2005-04-13 + * Merged hierarchical type/role patch from Tresys Technology. + * Merged MLS fixes from Darrel Goeddel of TCS. + +1.22 2005-03-09 + * Updated version for release. + +1.21.4 2005-02-17 + * Moved genpolusers utility to libsepol. + * Merged range_transition support from Darrel Goeddel (TCS). + +1.21.3 2005-02-16 + * Merged define_user() cleanup patch from Darrel Goeddel (TCS). + +1.21.2 2005-02-09 + * Changed relabel Makefile target to use restorecon. + +1.21.1 2005-01-26 + * Merged enhanced MLS support from Darrel Goeddel (TCS). + +1.20 2005-01-04 + * Merged typeattribute statement patch from Darrel Goeddel of TCS. + * Changed genpolusers to handle multiple user config files. + * Merged nodecon ordering patch from Chad Hanson of TCS. + +1.18 2004-10-07 + * MLS build fix. + * Fixed Makefile dependencies (Chris PeBenito). + * Merged fix for role dominance ordering issue from Chad Hanson of TCS. + * Preserve portcon ordering and apply more checking. + +1.16 2004-08-13 + * Allow empty conditional clauses. + * Moved genpolbools utility to libsepol. + * Updated for libsepol set functions. + * Changed to link with libsepol.a. + * Moved core functionality into libsepol. + * Merged bug fix for conditional self handling from Karl MacMillan, Dave Caplan, and Joshua Brindle of Tresys. + * Added genpolusers program. + * Fixed bug in checkpolicy conditional code. + +1.14 2004-06-28 + * Merged fix for MLS logic from Daniel Thayer of TCS. + * Require semicolon terminator for typealias statement. + +1.12 2004-06-16 + * Merged fine-grained netlink class support. + +1.10 2004-04-07 + * Merged ipv6 support from James Morris of RedHat. + * Fixed compute_av bug discovered by Chad Hanson of TCS. + +1.8 2004-03-09 + * Merged policydb MLS patch from Chad Hanson of TCS. + * Fixed mmap of policy file. + +1.6 2004-02-18 + * Merged conditional policy extensions from Tresys Technology. + * Added typealias declaration support per Russell Coker's request. + * Added support for excluding types from type sets based on + a patch by David Caplan, but reimplemented as a change to the + policy grammar. + * Merged patch from Colin Walters to report source file name and line + number for errors when available. + * Un-deprecated role transitions. + +1.4 2003-12-01 + * Regenerated headers. + * Merged patches from Bastian Blank and Joerg Hoh. + +1.2 2003-09-30 + * Merged MLS build patch from Karl MacMillan of Tresys. + * Merged checkpolicy man page from Magosanyi Arpad. + +1.1 2003-08-13 + * Fixed endian bug in policydb_write for behavior value. + * License -> GPL. + * Merged coding style cleanups from James Morris. + +1.0 2003-07-11 + * Initial public release. +
diff --git a/selinux/checkpolicy/Makefile b/selinux/checkpolicy/Makefile new file mode 100644 index 0000000..53a3074 --- /dev/null +++ b/selinux/checkpolicy/Makefile
@@ -0,0 +1,65 @@ +# +# Makefile for building the checkpolicy program +# +PREFIX ?= $(DESTDIR)/usr +BINDIR ?= $(PREFIX)/bin +MANDIR ?= $(PREFIX)/share/man +LIBDIR ?= $(PREFIX)/lib +INCLUDEDIR ?= $(PREFIX)/include +TARGETS = checkpolicy checkmodule + +LEX = flex +YACC = bison -y + +CFLAGS ?= -g -Wall -Werror -Wshadow -O2 -pipe -fno-strict-aliasing + +override CFLAGS += -I. -I${INCLUDEDIR} + +CHECKOBJS = y.tab.o lex.yy.o queue.o module_compiler.o parse_util.o \ + policy_define.o +CHECKPOLOBJS = $(CHECKOBJS) checkpolicy.o +CHECKMODOBJS = $(CHECKOBJS) checkmodule.o + +LDLIBS=$(LIBDIR)/libsepol.a -lfl + +GENERATED=lex.yy.c y.tab.c y.tab.h + +all: $(TARGETS) + $(MAKE) -C test + +checkpolicy: $(CHECKPOLOBJS) + +checkmodule: $(CHECKMODOBJS) + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +y.tab.o: y.tab.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $< + +lex.yy.o: lex.yy.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $< + +y.tab.c: policy_parse.y + $(YACC) -d policy_parse.y + +lex.yy.c: policy_scan.l y.tab.c + $(LEX) policy_scan.l + +install: all + -mkdir -p $(BINDIR) + -mkdir -p $(MANDIR)/man8 + install -m 755 $(TARGETS) $(BINDIR) + install -m 644 checkpolicy.8 $(MANDIR)/man8 + install -m 644 checkmodule.8 $(MANDIR)/man8 + +relabel: install + /sbin/restorecon $(BINDIR)/checkpolicy + /sbin/restorecon $(BINDIR)/checkmodule + +clean: + -rm -f $(TARGETS) $(CHECKPOLOBJS) $(CHECKMODOBJS) y.tab.c y.tab.h lex.yy.c + $(MAKE) -C test clean + +indent: + ../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch]))
diff --git a/selinux/checkpolicy/VERSION b/selinux/checkpolicy/VERSION new file mode 100644 index 0000000..95e3ba8 --- /dev/null +++ b/selinux/checkpolicy/VERSION
@@ -0,0 +1 @@ +2.5
diff --git a/selinux/checkpolicy/checkmodule.8 b/selinux/checkpolicy/checkmodule.8 new file mode 100644 index 0000000..ee95882 --- /dev/null +++ b/selinux/checkpolicy/checkmodule.8
@@ -0,0 +1,67 @@ +.TH CHECKMODULE 8 +.SH NAME +checkmodule \- SELinux policy module compiler +.SH SYNOPSIS +.B checkmodule +.I "[\-h] [\-b] [\-C] [\-m] [\-M] [\-U handle_unknown ] [\-V] [\-o output_file] [input_file]" +.SH "DESCRIPTION" +This manual page describes the +.BR checkmodule +command. +.PP +.B checkmodule +is a program that checks and compiles a SELinux security policy module +into a binary representation. It can generate either a base policy +module (default) or a non-base policy module (\-m option); typically, +you would build a non-base policy module to add to an existing module +store that already has a base module provided by the base policy. Use +semodule_package to combine this module with its optional file +contexts to create a policy package, and then use semodule to install +the module package into the module store and load the resulting policy. + +.SH OPTIONS +.TP +.B \-b,\-\-binary +Read an existing binary policy module file rather than a source policy +module file. This option is a development/debugging aid. +.TP +.B \-C,\-\-cil +Write CIL policy file rather than binary policy file. +.TP +.B \-h,\-\-help +Print usage. +.TP +.B \-m +Generate a non-base policy module. +.TP +.B \-M,\-\-mls +Enable the MLS/MCS support when checking and compiling the policy module. +.TP +.B \-V,\-\-version + Show policy versions created by this program. Note that you cannot currently build older versions. +.TP +.B \-o,\-\-output filename +Write a binary policy module file to the specified filename. +Otherwise, checkmodule will only check the syntax of the module source file +and will not generate a binary module at all. +.TP +.B \-U,\-\-handle-unknown <action> +Specify how the kernel should handle unknown classes or permissions (deny, allow or reject). + +.SH EXAMPLE +.nf +# Build a MLS/MCS-enabled non-base policy module. +$ checkmodule \-M \-m httpd.te \-o httpd.mod +.fi + +.SH "SEE ALSO" +.B semodule(8), semodule_package(8) +SELinux documentation at http://www.nsa.gov/research/selinux, +especially "Configuring the SELinux Policy". + + +.SH AUTHOR +This manual page was copied from the checkpolicy man page +written by Arpad Magosanyi <mag@bunuel.tii.matav.hu>, +and edited by Dan Walsh <dwalsh@redhat.com>. +The program was written by Stephen Smalley <sds@epoch.ncsc.mil>.
diff --git a/selinux/checkpolicy/checkmodule.c b/selinux/checkpolicy/checkmodule.c new file mode 100644 index 0000000..53cc5a0 --- /dev/null +++ b/selinux/checkpolicy/checkmodule.c
@@ -0,0 +1,343 @@ +/* + * Authors: Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * + * Copyright (C) 2004-5 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +#include <getopt.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <sys/mman.h> +#include <libgen.h> + +#include <sepol/module_to_cil.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/sidtab.h> + +#include "queue.h" +#include "checkpolicy.h" +#include "parse_util.h" + +extern char *optarg; +extern int optind; + +static sidtab_t sidtab; + +extern int mlspol; + +static int handle_unknown = SEPOL_DENY_UNKNOWN; +static const char *txtfile = "policy.conf"; +static const char *binfile = "policy"; + +unsigned int policy_type = POLICY_BASE; +unsigned int policyvers = MOD_POLICYDB_VERSION_MAX; + +static int read_binary_policy(policydb_t * p, const char *file, const char *progname) +{ + int fd; + struct stat sb; + void *map; + struct policy_file f, *fp; + + fd = open(file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open '%s': %s\n", + file, strerror(errno)); + return -1; + } + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Can't stat '%s': %s\n", + file, strerror(errno)); + close(fd); + return -1; + } + map = + mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + close(fd); + if (map == MAP_FAILED) { + fprintf(stderr, "Can't map '%s': %s\n", file, strerror(errno)); + return -1; + } + policy_file_init(&f); + f.type = PF_USE_MEMORY; + f.data = map; + f.len = sb.st_size; + fp = &f; + + if (policydb_init(p)) { + fprintf(stderr, "%s: policydb_init: Out of memory!\n", + progname); + return -1; + } + if (policydb_read(p, fp, 1)) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + progname); + return -1; + } + + /* Check Policy Consistency */ + if (p->mls) { + if (!mlspol) { + fprintf(stderr, "%s: MLS policy, but non-MLS" + " is specified\n", progname); + return -1; + } + } else { + if (mlspol) { + fprintf(stderr, "%s: non-MLS policy, but MLS" + " is specified\n", progname); + return -1; + } + } + return 0; +} + +static int write_binary_policy(policydb_t * p, FILE *outfp) +{ + struct policy_file pf; + + p->policy_type = policy_type; + p->policyvers = policyvers; + p->handle_unknown = handle_unknown; + + policy_file_init(&pf); + pf.type = PF_USE_STDIO; + pf.fp = outfp; + return policydb_write(p, &pf); +} + +static void usage(char *progname) +{ + printf("usage: %s [-h] [-V] [-b] [-C] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname); + printf("Build base and policy modules.\n"); + printf("Options:\n"); + printf(" INPUT build module from INPUT (else read from \"%s\")\n", + txtfile); + printf(" -V show policy versions created by this program\n"); + printf(" -b treat input as a binary policy file\n"); + printf(" -C output CIL policy instead of binary policy\n"); + printf(" -h print usage\n"); + printf(" -U OPTION How to handle unknown classes and permissions\n"); + printf(" deny: Deny unknown kernel checks\n"); + printf(" reject: Reject loading of policy with unknowns\n"); + printf(" allow: Allow unknown kernel checks\n"); + printf(" -m build a policy module instead of a base module\n"); + printf(" -M enable MLS policy\n"); + printf(" -o FILE write module to FILE (else just check syntax)\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *file = txtfile, *outfile = NULL; + unsigned int binary = 0, cil = 0; + int ch; + int show_version = 0; + policydb_t modpolicydb; + struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"output", required_argument, NULL, 'o'}, + {"binary", no_argument, NULL, 'b'}, + {"version", no_argument, NULL, 'V'}, + {"handle-unknown", required_argument, NULL, 'U'}, + {"mls", no_argument, NULL, 'M'}, + {"cil", no_argument, NULL, 'C'}, + {NULL, 0, NULL, 0} + }; + + while ((ch = getopt_long(argc, argv, "ho:bVU:mMC", long_options, NULL)) != -1) { + switch (ch) { + case 'h': + usage(argv[0]); + break; + case 'o': + outfile = optarg; + break; + case 'b': + binary = 1; + file = binfile; + break; + case 'V': + show_version = 1; + break; + case 'U': + if (!strcasecmp(optarg, "deny")) { + handle_unknown = DENY_UNKNOWN; + break; + } + if (!strcasecmp(optarg, "reject")) { + handle_unknown = REJECT_UNKNOWN; + break; + } + if (!strcasecmp(optarg, "allow")) { + handle_unknown = ALLOW_UNKNOWN; + break; + } + usage(argv[0]); + case 'm': + policy_type = POLICY_MOD; + policyvers = MOD_POLICYDB_VERSION_MAX; + break; + case 'M': + mlspol = 1; + break; + case 'C': + cil = 1; + break; + default: + usage(argv[0]); + } + } + + if (show_version) { + printf("Module versions %d-%d\n", + MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX); + exit(0); + } + + if (handle_unknown && (policy_type != POLICY_BASE)) { + fprintf(stderr, "%s: Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]); + exit(1); + } + + if (binary && (policy_type != POLICY_BASE)) { + fprintf(stderr, "%s: -b and -m are incompatible with each other.\n", argv[0]); + exit(1); + } + + if (optind != argc) { + file = argv[optind++]; + if (optind != argc) + usage(argv[0]); + } + printf("%s: loading policy configuration from %s\n", argv[0], file); + + /* Set policydb and sidtab used by libsepol service functions + to my structures, so that I can directly populate and + manipulate them. */ + sepol_set_policydb(&modpolicydb); + sepol_set_sidtab(&sidtab); + + if (binary) { + if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) { + exit(1); + } + } else { + if (policydb_init(&modpolicydb)) { + fprintf(stderr, "%s: out of memory!\n", argv[0]); + return -1; + } + + modpolicydb.policy_type = policy_type; + modpolicydb.mls = mlspol; + modpolicydb.handle_unknown = handle_unknown; + + if (read_source_policy(&modpolicydb, file, argv[0]) == -1) { + exit(1); + } + + if (hierarchy_check_constraints(NULL, &modpolicydb)) { + return -1; + } + } + + if (policy_type != POLICY_BASE && outfile) { + char *mod_name = modpolicydb.name; + char *out_path = strdup(outfile); + if (out_path == NULL) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(1); + } + char *out_name = basename(out_path); + char *separator = strrchr(out_name, '.'); + if (separator) { + *separator = '\0'; + } + if (strcmp(mod_name, out_name) != 0) { + fprintf(stderr, "%s: Module name %s is different than the output base filename %s\n", argv[0], mod_name, out_name); + exit(1); + } + free(out_path); + } + + if (modpolicydb.policy_type == POLICY_BASE && !cil) { + /* Verify that we can successfully expand the base module. */ + policydb_t kernpolicydb; + + if (policydb_init(&kernpolicydb)) { + fprintf(stderr, "%s: policydb_init failed\n", argv[0]); + exit(1); + } + if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) { + fprintf(stderr, "%s: link modules failed\n", argv[0]); + exit(1); + } + if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) { + fprintf(stderr, "%s: expand module failed\n", argv[0]); + exit(1); + } + policydb_destroy(&kernpolicydb); + } + + if (policydb_load_isids(&modpolicydb, &sidtab)) + exit(1); + + sepol_sidtab_destroy(&sidtab); + + printf("%s: policy configuration loaded\n", argv[0]); + + if (outfile) { + FILE *outfp = fopen(outfile, "w"); + + if (!outfp) { + perror(outfile); + exit(1); + } + + if (!cil) { + printf("%s: writing binary representation (version %d) to %s\n", + argv[0], policyvers, outfile); + + if (write_binary_policy(&modpolicydb, outfp) != 0) { + fprintf(stderr, "%s: error writing %s\n", argv[0], outfile); + exit(1); + } + } else { + printf("%s: writing CIL to %s\n",argv[0], outfile); + + if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) { + fprintf(stderr, "%s: error writing %s\n", argv[0], outfile); + exit(1); + } + } + + fclose(outfp); + } else if (cil) { + fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]); + exit(1); + } + + policydb_destroy(&modpolicydb); + + return 0; +} + +/* FLASK */
diff --git a/selinux/checkpolicy/checkpolicy.8 b/selinux/checkpolicy/checkpolicy.8 new file mode 100644 index 0000000..600d5cd --- /dev/null +++ b/selinux/checkpolicy/checkpolicy.8
@@ -0,0 +1,59 @@ +.TH CHECKPOLICY 8 +.SH NAME +checkpolicy \- SELinux policy compiler +.SH SYNOPSIS +.B checkpolicy +.I "[\-b] [\-C] [\-d] [\-M] [\-c policyvers] [\-o output_file] [input_file]" +.br +.SH "DESCRIPTION" +This manual page describes the +.BR checkpolicy +command. +.PP +.B checkpolicy +is a program that checks and compiles a SELinux security policy configuration +into a binary representation that can be loaded into the kernel. If no +input file name is specified, checkpolicy will attempt to read from +policy.conf or policy, depending on whether the \-b flag is specified. + +.SH OPTIONS +.TP +.B \-b,\-\-binary +Read an existing binary policy file rather than a source policy.conf file. +.TP +.B \-C,\-\-cil +Write CIL policy file rather than binary policy file. +.TP +.B \-d,\-\-debug +Enter debug mode after loading the policy. +.TP +.B \-M,\-\-mls +Enable the MLS policy when checking and compiling the policy. +.TP +.B \-o,\-\-output filename +Write a binary policy file to the specified filename. +.TP +.B \-c policyvers +Specify the policy version, defaults to the latest. +.TP +.B \-t,\-\-target +Specify the target platform (selinux or xen). +.TP +.B \-U,\-\-handle-unknown <action> +Specify how the kernel should handle unknown classes or permissions (deny, allow or reject). +.TP +.B \-V,\-\-version +Show version information. +.TP +.B \-h,\-\-help +Show usage information. + +.SH "SEE ALSO" +SELinux documentation at http://www.nsa.gov/research/selinux, +especially "Configuring the SELinux Policy". + + +.SH AUTHOR +This manual page was written by Arpad Magosanyi <mag@bunuel.tii.matav.hu>, +and edited by Stephen Smalley <sds@epoch.ncsc.mil>. +The program was written by Stephen Smalley <sds@epoch.ncsc.mil>.
diff --git a/selinux/checkpolicy/checkpolicy.c b/selinux/checkpolicy/checkpolicy.c new file mode 100644 index 0000000..2d68316 --- /dev/null +++ b/selinux/checkpolicy/checkpolicy.c
@@ -0,0 +1,1224 @@ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: Karl MacMillan <kmacmillan@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: James Morris <jmorris@intercode.com.au> + * + * Added IPv6 support. + * + * Updated: Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Policy Module support. + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * Copyright (C) 2003 - 2005 Tresys Technology, LLC + * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* FLASK */ + +/* + * checkpolicy + * + * Load and check a policy configuration. + * + * A policy configuration is created in a text format, + * and then compiled into a binary format for use by + * the security server. By default, checkpolicy reads + * the text format. If '-b' is specified, then checkpolicy + * reads the binary format instead. + * + * If '-o output_file' is specified, then checkpolicy + * writes the binary format version of the configuration + * to the specified output file. + * + * If '-d' is specified, then checkpolicy permits the user + * to interactively test the security server functions with + * the loaded policy configuration. + * + * If '-c' is specified, then the supplied parameter is used to + * determine which policy version to use for generating binary + * policy. This is for compatibility with older kernels. If any + * booleans or conditional rules are thrown away a warning is printed. + */ + +#include <getopt.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif +#include <arpa/inet.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <sys/mman.h> + +#ifdef __APPLE__ +#include <ctype.h> +#endif + +#include <sepol/module_to_cil.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/link.h> + +#include "queue.h" +#include "checkpolicy.h" +#include "parse_util.h" + +extern char *optarg; +extern int optind; + +static policydb_t policydb; +static sidtab_t sidtab; + +extern policydb_t *policydbp; +extern int mlspol; + +static int handle_unknown = SEPOL_DENY_UNKNOWN; +static const char *txtfile = "policy.conf"; +static const char *binfile = "policy"; + +unsigned int policyvers = POLICYDB_VERSION_MAX; + +void usage(char *progname) +{ + printf + ("usage: %s [-b] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M]" + "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]" + "[input_file]\n", + progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); + exit(1); +} + +#define FGETS(out, size, in) \ +if (fgets(out,size,in)==NULL) { \ + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\ + strerror(errno)); \ + exit(1);\ +} +static int print_sid(sepol_security_id_t sid, + context_struct_t * context + __attribute__ ((unused)), void *data + __attribute__ ((unused))) +{ + sepol_security_context_t scontext; + size_t scontext_len; + int rc; + + rc = sepol_sid_to_context(sid, &scontext, &scontext_len); + if (rc) + printf("sid %d -> error %d\n", sid, rc); + else { + printf("sid %d -> scontext %s\n", sid, scontext); + free(scontext); + } + return 0; +} + +struct val_to_name { + unsigned int val; + char *name; +}; + +static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p) +{ + struct val_to_name *v = p; + perm_datum_t *perdatum; + + perdatum = (perm_datum_t *) datum; + + if (v->val == perdatum->s.value) { + v->name = key; + return 1; + } + + return 0; +} + +#ifdef EQUIVTYPES +static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d, + struct avtab_node *type_rules) +{ + struct avtab_node *p, *c, *n; + + for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) { + /* + * Find the insertion point, keeping the list + * ordered by source type, then target type, then + * target class. + */ + if (k->source_type < c->key.source_type) + break; + if (k->source_type == c->key.source_type && + k->target_type < c->key.target_type) + break; + if (k->source_type == c->key.source_type && + k->target_type == c->key.target_type && + k->target_class < c->key.target_class) + break; + } + + /* Insert the rule */ + n = malloc(sizeof(struct avtab_node)); + if (!n) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + + n->key = *k; + n->datum = *d; + n->next = p->next; + p->next = n; + return 0; +} + +static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args) +{ + struct avtab_node *type_rules = args; + + if (d->specified & AVTAB_ALLOWED) { + /* + * Insert the rule into the lists for both + * the source type and the target type. + */ + if (insert_type_rule(k, d, &type_rules[k->source_type - 1])) + return -1; + if (insert_type_rule(k, d, &type_rules[k->target_type - 1])) + return -1; + } + + return 0; +} + +static void free_type_rules(struct avtab_node *l) +{ + struct avtab_node *tmp; + + while (l) { + tmp = l; + l = l->next; + free(tmp); + } +} + +static int identify_equiv_types(void) +{ + struct avtab_node *type_rules, *l1, *l2; + int i, j; + + /* + * Create a list of access vector rules for each type + * from the access vector table. + */ + type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim); + if (!type_rules) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(type_rules, 0, + sizeof(struct avtab_node) * policydb.p_types.nprim); + if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules)) + exit(1); + + /* + * Compare the type lists and identify equivalent types. + */ + for (i = 0; i < policydb.p_types.nprim - 1; i++) { + if (!type_rules[i].next) + continue; + for (j = i + 1; j < policydb.p_types.nprim; j++) { + for (l1 = type_rules[i].next, l2 = type_rules[j].next; + l1 && l2; l1 = l1->next, l2 = l2->next) { + if (l2->key.source_type == (j + 1)) { + if (l1->key.source_type != (i + 1)) + break; + } else { + if (l1->key.source_type != + l2->key.source_type) + break; + } + if (l2->key.target_type == (j + 1)) { + if (l1->key.target_type != (i + 1)) + break; + } else { + if (l1->key.target_type != + l2->key.target_type) + break; + } + if (l1->key.target_class != l2->key.target_class + || l1->datum.allowed != l2->datum.allowed) + break; + } + if (l1 || l2) + continue; + free_type_rules(type_rules[j].next); + type_rules[j].next = NULL; + printf("Types %s and %s are equivalent.\n", + policydb.p_type_val_to_name[i], + policydb.p_type_val_to_name[j]); + } + free_type_rules(type_rules[i].next); + type_rules[i].next = NULL; + } + + free(type_rules); + return 0; +} +#endif + +extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av); + +int display_bools(void) +{ + uint32_t i; + + for (i = 0; i < policydbp->p_bools.nprim; i++) { + printf("%s : %d\n", policydbp->p_bool_val_to_name[i], + policydbp->bool_val_to_struct[i]->state); + } + return 0; +} + +void display_expr(cond_expr_t * exp) +{ + + cond_expr_t *cur; + for (cur = exp; cur != NULL; cur = cur->next) { + switch (cur->expr_type) { + case COND_BOOL: + printf("%s ", + policydbp->p_bool_val_to_name[cur->bool - 1]); + break; + case COND_NOT: + printf("! "); + break; + case COND_OR: + printf("|| "); + break; + case COND_AND: + printf("&& "); + break; + case COND_XOR: + printf("^ "); + break; + case COND_EQ: + printf("== "); + break; + case COND_NEQ: + printf("!= "); + break; + default: + printf("error!"); + break; + } + } +} + +int display_cond_expressions(void) +{ + cond_node_t *cur; + + for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) { + printf("expression: "); + display_expr(cur->expr); + printf("current state: %d\n", cur->cur_state); + } + return 0; +} + +int change_bool(char *name, int state) +{ + cond_bool_datum_t *bool; + + bool = hashtab_search(policydbp->p_bools.table, name); + if (bool == NULL) { + printf("Could not find bool %s\n", name); + return -1; + } + bool->state = state; + evaluate_conds(policydbp); + return 0; +} + +static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused))) +{ + level_datum_t *levdatum = (level_datum_t *) datum; + + if (!levdatum->isalias && !levdatum->defined) { + fprintf(stderr, + "Error: sensitivity %s was not used in a level definition!\n", + key); + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + policydb_t parse_policy; + sepol_security_class_t tclass; + sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid; + sepol_security_context_t scontext; + struct sepol_av_decision avd; + class_datum_t *cladatum; + const char *file = txtfile; + char ans[80 + 1], *outfile = NULL, *path, *fstype; + size_t scontext_len, pathlen; + unsigned int i; + unsigned int protocol, port; + unsigned int binary = 0, debug = 0, cil = 0; + struct val_to_name v; + int ret, ch, fd, target = SEPOL_TARGET_SELINUX; + unsigned int nel, uret; + struct stat sb; + void *map; + FILE *outfp = NULL; + char *name; + int state; + int show_version = 0; + char *reason_buf = NULL; + unsigned int reason; + int flags; + struct policy_file pf; + struct option long_options[] = { + {"output", required_argument, NULL, 'o'}, + {"target", required_argument, NULL, 't'}, + {"binary", no_argument, NULL, 'b'}, + {"debug", no_argument, NULL, 'd'}, + {"version", no_argument, NULL, 'V'}, + {"handle-unknown", required_argument, NULL, 'U'}, + {"mls", no_argument, NULL, 'M'}, + {"cil", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + while ((ch = getopt_long(argc, argv, "o:t:dbU:MCVc:h", long_options, NULL)) != -1) { + switch (ch) { + case 'o': + outfile = optarg; + break; + case 't': + if (!strcasecmp(optarg, "Xen")) + target = SEPOL_TARGET_XEN; + else if (!strcasecmp(optarg, "SELinux")) + target = SEPOL_TARGET_SELINUX; + else{ + fprintf(stderr, "%s: Unknown target platform:" + "%s\n", argv[0], optarg); + exit(1); + } + break; + case 'b': + binary = 1; + file = binfile; + break; + case 'd': + debug = 1; + break; + case 'V': + show_version = 1; + break; + case 'U': + if (!strcasecmp(optarg, "deny")) { + handle_unknown = DENY_UNKNOWN; + break; + } + if (!strcasecmp(optarg, "allow")) { + handle_unknown = ALLOW_UNKNOWN; + break; + } + if (!strcasecmp(optarg, "reject")) { + handle_unknown = REJECT_UNKNOWN; + break; + } + usage(argv[0]); + case 'M': + mlspol = 1; + break; + case 'C': + cil = 1; + break; + case 'c':{ + long int n; + errno = 0; + n = strtol(optarg, NULL, 10); + if (errno) { + fprintf(stderr, + "Invalid policyvers specified: %s\n", + optarg); + usage(argv[0]); + exit(1); + } + if (n < POLICYDB_VERSION_MIN + || n > POLICYDB_VERSION_MAX) { + fprintf(stderr, + "policyvers value %ld not in range %d-%d\n", + n, POLICYDB_VERSION_MIN, + POLICYDB_VERSION_MAX); + usage(argv[0]); + exit(1); + } + if (policyvers != n) + policyvers = n; + break; + } + case 'h': + default: + usage(argv[0]); + } + } + + if (show_version) { + printf("%d (compatibility range %d-%d)\n", policyvers, + POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN); + exit(0); + } + + if (optind != argc) { + file = argv[optind++]; + if (optind != argc) + usage(argv[0]); + } + printf("%s: loading policy configuration from %s\n", argv[0], file); + + /* Set policydb and sidtab used by libsepol service functions + to my structures, so that I can directly populate and + manipulate them. */ + sepol_set_policydb(&policydb); + sepol_set_sidtab(&sidtab); + + if (binary) { + if (cil) { + fprintf(stderr, "%s: Converting kernel policy to CIL is not supported\n", + argv[0]); + exit(1); + } + fd = open(file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open '%s': %s\n", + file, strerror(errno)); + exit(1); + } + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Can't stat '%s': %s\n", + file, strerror(errno)); + exit(1); + } + map = + mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, "Can't map '%s': %s\n", + file, strerror(errno)); + exit(1); + } + policy_file_init(&pf); + pf.type = PF_USE_MEMORY; + pf.data = map; + pf.len = sb.st_size; + if (policydb_init(&policydb)) { + fprintf(stderr, "%s: policydb_init: Out of memory!\n", + argv[0]); + exit(1); + } + ret = policydb_read(&policydb, &pf, 1); + if (ret) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + argv[0]); + exit(1); + } + policydbp = &policydb; + + /* Check Policy Consistency */ + if (policydbp->mls) { + if (!mlspol) { + fprintf(stderr, "%s: MLS policy, but non-MLS" + " is specified\n", argv[0]); + exit(1); + } + } else { + if (mlspol) { + fprintf(stderr, "%s: non-MLS policy, but MLS" + " is specified\n", argv[0]); + exit(1); + } + } + } else { + if (policydb_init(&parse_policy)) + exit(1); + /* We build this as a base policy first since that is all the parser understands */ + parse_policy.policy_type = POLICY_BASE; + policydb_set_target_platform(&parse_policy, target); + + /* Let sepol know if we are dealing with MLS support */ + parse_policy.mls = mlspol; + parse_policy.handle_unknown = handle_unknown; + + policydbp = &parse_policy; + + if (read_source_policy(policydbp, file, "checkpolicy") < 0) + exit(1); + + if (hashtab_map(policydbp->p_levels.table, check_level, NULL)) + exit(1); + + /* Linking takes care of optional avrule blocks */ + if (link_modules(NULL, policydbp, NULL, 0, 0)) { + fprintf(stderr, "Error while resolving optionals\n"); + exit(1); + } + + if (!cil) { + if (policydb_init(&policydb)) { + fprintf(stderr, "%s: policydb_init failed\n", argv[0]); + exit(1); + } + if (expand_module(NULL, policydbp, &policydb, 0, 1)) { + fprintf(stderr, "Error while expanding policy\n"); + exit(1); + } + policydb_destroy(policydbp); + policydbp = &policydb; + } + } + + if (policydb_load_isids(&policydb, &sidtab)) + exit(1); + + printf("%s: policy configuration loaded\n", argv[0]); + + if (outfile) { + outfp = fopen(outfile, "w"); + if (!outfp) { + perror(outfile); + exit(1); + } + + policydb.policyvers = policyvers; + + if (!cil) { + printf + ("%s: writing binary representation (version %d) to %s\n", + argv[0], policyvers, outfile); + policydb.policy_type = POLICY_KERN; + + policy_file_init(&pf); + pf.type = PF_USE_STDIO; + pf.fp = outfp; + ret = policydb_write(&policydb, &pf); + if (ret) { + fprintf(stderr, "%s: error writing %s\n", + argv[0], outfile); + exit(1); + } + } else { + printf("%s: writing CIL to %s\n",argv[0], outfile); + ret = sepol_module_policydb_to_cil(outfp, policydbp, 1); + if (ret) { + fprintf(stderr, "%s: error writing %s\n", argv[0], outfile); + exit(1); + } + } + + if (outfile) { + fclose(outfp); + } + } else if (cil) { + fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]); + exit(1); + } + + if (!debug) { + policydb_destroy(&policydb); + exit(0); + } + + menu: + printf("\nSelect an option:\n"); + printf("0) Call compute_access_vector\n"); + printf("1) Call sid_to_context\n"); + printf("2) Call context_to_sid\n"); + printf("3) Call transition_sid\n"); + printf("4) Call member_sid\n"); + printf("5) Call change_sid\n"); + printf("6) Call list_sids\n"); + printf("7) Call load_policy\n"); + printf("8) Call fs_sid\n"); + printf("9) Call port_sid\n"); + printf("a) Call netif_sid\n"); + printf("b) Call node_sid\n"); + printf("c) Call fs_use\n"); + printf("d) Call genfs_sid\n"); + printf("e) Call get_user_sids\n"); + printf("f) display conditional bools\n"); + printf("g) display conditional expressions\n"); + printf("h) change a boolean value\n"); + printf("i) display constraint expressions\n"); + printf("j) display validatetrans expressions\n"); +#ifdef EQUIVTYPES + printf("z) Show equivalent types\n"); +#endif + printf("m) Show menu again\n"); + printf("q) Exit\n"); + while (1) { + printf("\nChoose: "); + FGETS(ans, sizeof(ans), stdin); + switch (ans[0]) { + case '0': + printf("source sid? "); + FGETS(ans, sizeof(ans), stdin); + ssid = atoi(ans); + + printf("target sid? "); + FGETS(ans, sizeof(ans), stdin); + tsid = atoi(ans); + + printf("target class? "); + FGETS(ans, sizeof(ans), stdin); + if (isdigit(ans[0])) { + tclass = atoi(ans); + if (!tclass + || tclass > policydb.p_classes.nprim) { + printf("\nNo such class.\n"); + break; + } + cladatum = + policydb.class_val_to_struct[tclass - 1]; + } else { + ans[strlen(ans) - 1] = 0; + cladatum = + (class_datum_t *) hashtab_search(policydb. + p_classes. + table, + ans); + if (!cladatum) { + printf("\nNo such class\n"); + break; + } + tclass = cladatum->s.value; + } + + if (!cladatum->comdatum && !cladatum->permissions.nprim) { + printf + ("\nNo access vector definition for that class\n"); + break; + } + ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd); + switch (ret) { + case 0: + printf("\nallowed {"); + for (i = 1; i <= sizeof(avd.allowed) * 8; i++) { + if (avd.allowed & (1 << (i - 1))) { + v.val = i; + ret = + hashtab_map(cladatum-> + permissions. + table, + find_perm, &v); + if (!ret && cladatum->comdatum) { + ret = + hashtab_map + (cladatum-> + comdatum-> + permissions.table, + find_perm, &v); + } + if (ret) + printf(" %s", v.name); + } + } + printf(" }\n"); + break; + case -EINVAL: + printf("\ninvalid sid\n"); + break; + default: + printf("return code 0x%x\n", ret); + } + break; + case '1': + printf("sid? "); + FGETS(ans, sizeof(ans), stdin); + ssid = atoi(ans); + ret = sepol_sid_to_context(ssid, + &scontext, &scontext_len); + switch (ret) { + case 0: + printf("\nscontext %s\n", scontext); + free(scontext); + break; + case -EINVAL: + printf("\ninvalid sid\n"); + break; + case -ENOMEM: + printf("\nout of memory\n"); + break; + default: + printf("return code 0x%x\n", ret); + } + break; + case '2': + printf("scontext? "); + FGETS(ans, sizeof(ans), stdin); + scontext_len = strlen(ans); + ans[scontext_len - 1] = 0; + ret = sepol_context_to_sid(ans, scontext_len, &ssid); + switch (ret) { + case 0: + printf("\nsid %d\n", ssid); + break; + case -EINVAL: + printf("\ninvalid context\n"); + break; + case -ENOMEM: + printf("\nout of memory\n"); + break; + default: + printf("return code 0x%x\n", ret); + } + break; + case '3': + case '4': + case '5': + ch = ans[0]; + + printf("source sid? "); + FGETS(ans, sizeof(ans), stdin); + ssid = atoi(ans); + printf("target sid? "); + FGETS(ans, sizeof(ans), stdin); + tsid = atoi(ans); + + printf("object class? "); + FGETS(ans, sizeof(ans), stdin); + if (isdigit(ans[0])) { + tclass = atoi(ans); + if (!tclass + || tclass > policydb.p_classes.nprim) { + printf("\nNo such class.\n"); + break; + } + } else { + ans[strlen(ans) - 1] = 0; + cladatum = + (class_datum_t *) hashtab_search(policydb. + p_classes. + table, + ans); + if (!cladatum) { + printf("\nNo such class\n"); + break; + } + tclass = cladatum->s.value; + } + + if (ch == '3') + ret = + sepol_transition_sid(ssid, tsid, tclass, + &ssid); + else if (ch == '4') + ret = + sepol_member_sid(ssid, tsid, tclass, &ssid); + else + ret = + sepol_change_sid(ssid, tsid, tclass, &ssid); + switch (ret) { + case 0: + printf("\nsid %d\n", ssid); + break; + case -EINVAL: + printf("\ninvalid sid\n"); + break; + case -ENOMEM: + printf("\nout of memory\n"); + break; + default: + printf("return code 0x%x\n", ret); + } + break; + case '6': + sepol_sidtab_map(&sidtab, print_sid, 0); + break; + case '7': + printf("pathname? "); + FGETS(ans, sizeof(ans), stdin); + pathlen = strlen(ans); + ans[pathlen - 1] = 0; + printf("%s: loading policy configuration from %s\n", + argv[0], ans); + fd = open(ans, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open '%s': %s\n", + ans, strerror(errno)); + break; + } + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Can't stat '%s': %s\n", + ans, strerror(errno)); + break; + } + map = + mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, "Can't map '%s': %s\n", + ans, strerror(errno)); + break; + } + ret = sepol_load_policy(map, sb.st_size); + switch (ret) { + case 0: + printf("\nsuccess\n"); + break; + case -EINVAL: + printf("\ninvalid policy\n"); + break; + case -ENOMEM: + printf("\nout of memory\n"); + break; + default: + printf("return code 0x%x\n", ret); + } + break; + case '8': + printf("fs kdevname? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + sepol_fs_sid(ans, &ssid, &tsid); + printf("fs_sid %d default_file_sid %d\n", ssid, tsid); + break; + case '9': + printf("protocol? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP")) + protocol = IPPROTO_TCP; + else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP")) + protocol = IPPROTO_UDP; + else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP")) + protocol = IPPROTO_DCCP; + else { + printf("unknown protocol\n"); + break; + } + printf("port? "); + FGETS(ans, sizeof(ans), stdin); + port = atoi(ans); + sepol_port_sid(0, 0, protocol, port, &ssid); + printf("sid %d\n", ssid); + break; + case 'a': + printf("netif name? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + sepol_netif_sid(ans, &ssid, &tsid); + printf("if_sid %d default_msg_sid %d\n", ssid, tsid); + break; + case 'b':{ + char *p; + int family, len; + struct in_addr addr4; + struct in6_addr addr6; + + printf("protocol family? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + if (!strcasecmp(ans, "ipv4")) + family = AF_INET; + else if (!strcasecmp(ans, "ipv6")) + family = AF_INET6; + else { + printf("unknown protocol family\n"); + break; + } + + printf("node address? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + + if (family == AF_INET) { + p = (char *)&addr4; + len = sizeof(addr4); + } else { + p = (char *)&addr6; + len = sizeof(addr6); + } + + if (inet_pton(family, ans, p) < 1) { + printf("error parsing address\n"); + break; + } + + sepol_node_sid(family, p, len, &ssid); + printf("sid %d\n", ssid); + break; + } + case 'c': + printf("fstype? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + sepol_fs_use(ans, &uret, &ssid); + switch (uret) { + case SECURITY_FS_USE_XATTR: + printf("use xattr\n"); + break; + case SECURITY_FS_USE_TRANS: + printf("use transition SIDs\n"); + break; + case SECURITY_FS_USE_TASK: + printf("use task SIDs\n"); + break; + case SECURITY_FS_USE_GENFS: + printf("use genfs\n"); + break; + case SECURITY_FS_USE_NONE: + printf("no labeling support\n"); + break; + } + printf("sid %d\n", ssid); + break; + case 'd': + printf("fstype? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + fstype = strdup(ans); + printf("path? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + path = strdup(ans); + printf("object class? "); + FGETS(ans, sizeof(ans), stdin); + if (isdigit(ans[0])) { + tclass = atoi(ans); + if (!tclass + || tclass > policydb.p_classes.nprim) { + printf("\nNo such class.\n"); + break; + } + } else { + ans[strlen(ans) - 1] = 0; + cladatum = + (class_datum_t *) hashtab_search(policydb. + p_classes. + table, + ans); + if (!cladatum) { + printf("\nNo such class\n"); + break; + } + tclass = cladatum->s.value; + } + sepol_genfs_sid(fstype, path, tclass, &ssid); + printf("sid %d\n", ssid); + free(fstype); + free(path); + break; + case 'e': + printf("from SID? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + ssid = atoi(ans); + + printf("username? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + + ret = sepol_get_user_sids(ssid, ans, &sids, &nel); + switch (ret) { + case 0: + if (!nel) + printf("\nnone\n"); + for (i = 0; i < nel; i++) + print_sid(sids[i], NULL, NULL); + free(sids); + break; + case -ENOMEM: + printf("\nout of memory\n"); + break; + case -EINVAL: + printf("\ninvalid argument\n"); + break; + default: + printf("\nerror\n"); + break; + } + break; + case 'f': + display_bools(); + break; + case 'g': + display_cond_expressions(); + break; + case 'h': + printf("name? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + + name = malloc((strlen(ans) + 1) * sizeof(char)); + if (name == NULL) { + fprintf(stderr, "couldn't malloc string.\n"); + break; + } + strcpy(name, ans); + + printf("state? "); + FGETS(ans, sizeof(ans), stdin); + ans[strlen(ans) - 1] = 0; + + if (atoi(ans)) + state = 1; + else + state = 0; + + change_bool(name, state); + free(name); + break; + case 'i': + printf("source sid? "); + FGETS(ans, sizeof(ans), stdin); + ssid = atoi(ans); + + printf("target sid? "); + FGETS(ans, sizeof(ans), stdin); + tsid = atoi(ans); + + printf("target class? "); + FGETS(ans, sizeof(ans), stdin); + if (isdigit(ans[0])) { + tclass = atoi(ans); + if (!tclass + || tclass > policydb.p_classes.nprim) { + printf("\nNo such class.\n"); + break; + } + cladatum = + policydb.class_val_to_struct[tclass - 1]; + } else { + ans[strlen(ans) - 1] = 0; + cladatum = + (class_datum_t *) hashtab_search(policydb. + p_classes. + table, + ans); + if (!cladatum) { + printf("\nNo such class\n"); + break; + } + tclass = cladatum->s.value; + } + + flags = SHOW_GRANTED; + if (sepol_compute_av_reason_buffer(ssid, tsid, + tclass, 0, &avd, &reason, + &reason_buf, flags)) { + printf("\nconstraint error\n"); + break; + } + if (reason_buf) { + printf("\nConstraint expressions:\n%s", + reason_buf); + free(reason_buf); + } else { + printf("\nNo constraints found.\n"); + } + break; + case 'j': + printf("old sid? "); + FGETS(ans, sizeof(ans), stdin); + oldsid = atoi(ans); + + printf("new sid? "); + FGETS(ans, sizeof(ans), stdin); + newsid = atoi(ans); + + printf("task sid? "); + FGETS(ans, sizeof(ans), stdin); + tasksid = atoi(ans); + + printf("target class? "); + FGETS(ans, sizeof(ans), stdin); + if (isdigit(ans[0])) { + tclass = atoi(ans); + if (!tclass + || tclass > policydb.p_classes.nprim) { + printf("\nNo such class.\n"); + break; + } + cladatum = + policydb.class_val_to_struct[tclass - 1]; + } else { + ans[strlen(ans) - 1] = 0; + cladatum = + (class_datum_t *) hashtab_search(policydb. + p_classes. + table, + ans); + if (!cladatum) { + printf("\nNo such class\n"); + break; + } + tclass = cladatum->s.value; + } + + flags = SHOW_GRANTED; + if (sepol_validate_transition_reason_buffer(oldsid, + newsid, tasksid, tclass, + &reason_buf, flags)) { + printf("\nvalidatetrans error\n"); + break; + } + if (reason_buf) { + printf("\nValidatetrans expressions:\n%s", + reason_buf); + free(reason_buf); + } else { + printf( + "\nNo validatetrans expressions found.\n"); + } + break; +#ifdef EQUIVTYPES + case 'z': + identify_equiv_types(); + break; +#endif + case 'm': + goto menu; + case 'q': + exit(0); + break; + default: + printf("\nUnknown option %s.\n", ans); + } + } + + return 0; +} + +/* FLASK */
diff --git a/selinux/checkpolicy/checkpolicy.h b/selinux/checkpolicy/checkpolicy.h new file mode 100644 index 0000000..3868f1f --- /dev/null +++ b/selinux/checkpolicy/checkpolicy.h
@@ -0,0 +1,20 @@ +#ifndef _CHECKPOLICY_H_ +#define _CHECKPOLICY_H_ + +#include <sepol/policydb/ebitmap.h> + +typedef struct te_assert { + ebitmap_t stypes; + ebitmap_t ttypes; + ebitmap_t tclasses; + int self; + sepol_access_vector_t *avp; + unsigned long line; + struct te_assert *next; +} te_assert_t; + +te_assert_t *te_assertions; + +extern unsigned int policyvers; + +#endif
diff --git a/selinux/checkpolicy/module_compiler.c b/selinux/checkpolicy/module_compiler.c new file mode 100644 index 0000000..6e5483c --- /dev/null +++ b/selinux/checkpolicy/module_compiler.c
@@ -0,0 +1,1604 @@ +/* Author : Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * Added support for binary policy modules + * + * Copyright (C) 2004 - 2005 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +#include <assert.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/avrule_block.h> +#include <sepol/policydb/conditional.h> + +#include "queue.h" +#include "module_compiler.h" + +union stack_item_u { + avrule_block_t *avrule; + cond_list_t *cond_list; +}; + +typedef struct scope_stack { + union stack_item_u u; + int type; /* for above union: 1 = avrule block, 2 = conditional */ + avrule_decl_t *decl; /* if in an avrule block, which + * declaration is current */ + avrule_t *last_avrule; + int in_else; /* if in an avrule block, within ELSE branch */ + int require_given; /* 1 if this block had at least one require */ + struct scope_stack *parent, *child; +} scope_stack_t; + +extern policydb_t *policydbp; +extern queue_t id_queue; +extern int yyerror(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 *)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 *)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 *) 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 *) 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; +}
diff --git a/selinux/checkpolicy/module_compiler.h b/selinux/checkpolicy/module_compiler.h new file mode 100644 index 0000000..72c2d9b --- /dev/null +++ b/selinux/checkpolicy/module_compiler.h
@@ -0,0 +1,109 @@ +/* Author : Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * Added support for binary policy modules + * + * Copyright (C) 2004 - 2005 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +#ifndef MODULE_COMPILER_H +#define MODULE_COMPILER_H + +#include <sepol/policydb/hashtab.h> + +/* Called when checkpolicy begins to parse a policy -- either at the + * very beginning for a kernel/base policy, or after the module header + * for policy modules. Initialize the memory structures within. + * Return 0 on success, -1 on error. */ +int define_policy(int pass, int module_header_given); + +/* Declare a symbol declaration to the current avrule_decl. Check + * that insertion is allowed here and that the symbol does not already + * exist. Returns 0 on success, 1 if symbol was already there (caller + * needs to free() the datum), -1 if declarations not allowed, -2 for + * duplicate declarations, -3 for all else. + */ +int declare_symbol(uint32_t symbol_type, + hashtab_key_t key, hashtab_datum_t datum, + uint32_t * dest_value, uint32_t * datum_value); + +role_datum_t *declare_role(unsigned char isattr); +type_datum_t *declare_type(unsigned char primary, unsigned char isattr); +user_datum_t *declare_user(void); + +type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr); +role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr); + +/* Add a symbol to the current avrule_block's require section. Note + * that a module may not both declare and require the same symbol. + * Returns 0 on success, -1 on error. */ +int require_symbol(uint32_t symbol_type, + hashtab_key_t key, hashtab_datum_t datum, + uint32_t * dest_value, uint32_t * datum_value); + +/* Enable a permission for a class within the current avrule_decl. + * Return 0 on success, -1 if out of memory. */ +int add_perm_to_class(uint32_t perm_value, uint32_t class_value); + +/* Functions called from REQUIRE blocks. Add the first symbol on the + * id_queue to this avrule_decl's scope if not already there. + * c.f. require_symbol(). */ +int require_class(int pass); +int require_role(int pass); +int require_type(int pass); +int require_attribute(int pass); +int require_attribute_role(int pass); +int require_user(int pass); +int require_bool(int pass); +int require_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); + +#endif
diff --git a/selinux/checkpolicy/parse_util.c b/selinux/checkpolicy/parse_util.c new file mode 100644 index 0000000..9fda5b4 --- /dev/null +++ b/selinux/checkpolicy/parse_util.c
@@ -0,0 +1,78 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parse_util.h" +#include "queue.h" + +/* these are defined in policy_parse.y and are needed for read_source_policy */ +extern FILE *yyin; +extern void init_parser(int); +extern int yyparse(void); +extern void yyrestart(FILE *); +extern queue_t id_queue; +extern unsigned int policydb_errors; +extern unsigned long policydb_lineno; +extern policydb_t *policydbp; +extern int mlspol; +extern void set_source_file(const char *name); + +int read_source_policy(policydb_t * p, const char *file, const char *progname) +{ + yyin = fopen(file, "r"); + if (!yyin) { + fprintf(stderr, "%s: unable to open %s\n", progname, file); + return -1; + } + set_source_file(file); + + if ((id_queue = queue_create()) == NULL) { + fprintf(stderr, "%s: out of memory!\n", progname); + return -1; + } + + policydbp = p; + mlspol = p->mls; + + init_parser(1); + if (yyparse() || policydb_errors) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + progname); + return -1; + } + rewind(yyin); + init_parser(2); + set_source_file(file); + yyrestart(yyin); + if (yyparse() || policydb_errors) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + progname); + return -1; + } + queue_destroy(id_queue); + + if (policydb_errors) + return -1; + + fclose(yyin); + + return 0; +}
diff --git a/selinux/checkpolicy/parse_util.h b/selinux/checkpolicy/parse_util.h new file mode 100644 index 0000000..a80128a --- /dev/null +++ b/selinux/checkpolicy/parse_util.h
@@ -0,0 +1,35 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Utility functions shared by checkpolicy and checkmodule */ + +#ifndef __PARSE_UTIL_H__ +#define __PARSE_UTIL_H__ + +#include <sepol/policydb/policydb.h> + +/* Read a source policy and populate the policydb passed in. The + * policydb must already have been created and configured (e.g., + * expected policy type set. The string progname is used for + * error messages. No checking of assertions, hierarchy, etc. + * is done. */ +int read_source_policy(policydb_t * p, const char *file, const char *progname); + +#endif
diff --git a/selinux/checkpolicy/policy_define.c b/selinux/checkpolicy/policy_define.c new file mode 100644 index 0000000..100e517 --- /dev/null +++ b/selinux/checkpolicy/policy_define.c
@@ -0,0 +1,5476 @@ +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: David Caplan, <dac@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@mentalrootkit.com> + * Jason Tang <jtang@tresys.com> + * + * Added support for binary policy modules + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * Copyright (C) 2003 - 2008 Tresys Technology, LLC + * Copyright (C) 2007 Red Hat Inc. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* FLASK */ + +#include <sys/types.h> +#include <assert.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif +#include <arpa/inet.h> +#include <stdlib.h> +#include <limits.h> +#include <inttypes.h> +#include <ctype.h> + +#include <sepol/policydb/expand.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/polcaps.h> +#include "queue.h" +#include "checkpolicy.h" +#include "module_compiler.h" +#include "policy_define.h" + +policydb_t *policydbp; +queue_t id_queue = 0; +unsigned int pass; +char *curfile = 0; +int mlspol = 0; + +extern unsigned long policydb_lineno; +extern unsigned long source_lineno; +extern unsigned int policydb_errors; +extern 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); +} + +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; + } + return add_aliases_to_type(t); +} + +int define_typeattribute(void) +{ + char *id; + type_datum_t *t, *attr; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no type name for typeattribute definition?"); + return -1; + } + + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + return -1; + } + t = hashtab_search(policydbp->p_types.table, id); + if (!t || t->flavor == TYPE_ATTRIB) { + yyerror2("unknown type %s", id); + free(id); + return -1; + } + + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("attribute %s is not within scope", id); + free(id); + return -1; + } + attr = hashtab_search(policydbp->p_types.table, id); + if (!attr) { + /* treat it as a fatal error */ + yyerror2("attribute %s is not declared", id); + free(id); + return -1; + } + + if (attr->flavor != TYPE_ATTRIB) { + yyerror2("%s is a type, not an attribute", id); + free(id); + return -1; + } + + if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { + yyerror("Out of memory!"); + return -1; + } + + if (ebitmap_set_bit(&attr->types, (t->s.value - 1), TRUE)) { + yyerror("out of memory"); + return -1; + } + } + + return 0; +} + +static int define_typebounds_helper(char *bounds_id, char *type_id) +{ + type_datum_t *bounds, *type; + + if (!is_id_in_scope(SYM_TYPES, bounds_id)) { + yyerror2("type %s is not within scope", bounds_id); + return -1; + } + + bounds = hashtab_search(policydbp->p_types.table, bounds_id); + if (!bounds || bounds->flavor == TYPE_ATTRIB) { + yyerror2("hoge unknown type %s", bounds_id); + return -1; + } + + if (!is_id_in_scope(SYM_TYPES, type_id)) { + yyerror2("type %s is not within scope", type_id); + return -1; + } + + type = hashtab_search(policydbp->p_types.table, type_id); + if (!type || type->flavor == TYPE_ATTRIB) { + yyerror2("type %s is not declared", type_id); + return -1; + } + + if (type->flavor == TYPE_TYPE && !type->primary) { + type = policydbp->type_val_to_struct[type->s.value - 1]; + } else if (type->flavor == TYPE_ALIAS) { + type = policydbp->type_val_to_struct[type->primary - 1]; + } + + if (!type->bounds) + type->bounds = bounds->s.value; + else if (type->bounds != bounds->s.value) { + yyerror2("type %s has inconsistent master {%s,%s}", + type_id, + policydbp->p_type_val_to_name[type->bounds - 1], + policydbp->p_type_val_to_name[bounds->s.value - 1]); + return -1; + } + + return 0; +} + +int define_typebounds(void) +{ + char *bounds, *id; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + bounds = (char *) queue_remove(id_queue); + if (!bounds) { + yyerror("no type name for typebounds definition?"); + return -1; + } + + while ((id = queue_remove(id_queue))) { + if (define_typebounds_helper(bounds, id)) + return -1; + free(id); + } + free(bounds); + + return 0; +} + +int define_type(int alias) +{ + char *id; + type_datum_t *datum, *attr; + + if (pass == 2) { + /* + * If type name contains ".", we have to define boundary + * relationship implicitly to keep compatibility with + * old name based hierarchy. + */ + if ((id = queue_remove(id_queue))) { + char *bounds, *delim; + + if ((delim = strrchr(id, '.')) + && (bounds = strdup(id))) { + bounds[(size_t)(delim - id)] = '\0'; + + if (define_typebounds_helper(bounds, id)) + return -1; + free(bounds); + } + free(id); + } + + if (alias) { + while ((id = queue_remove(id_queue))) + free(id); + } + + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + if ((datum = declare_type(TRUE, FALSE)) == NULL) { + return -1; + } + + if (alias) { + if (add_aliases_to_type(datum) == -1) { + return -1; + } + } + + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("attribute %s is not within scope", id); + free(id); + return -1; + } + attr = hashtab_search(policydbp->p_types.table, id); + if (!attr) { + /* treat it as a fatal error */ + yyerror2("attribute %s is not declared", id); + return -1; + } + + if (attr->flavor != TYPE_ATTRIB) { + yyerror2("%s is a type, not an attribute", id); + return -1; + } + + if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { + yyerror("Out of memory!"); + return -1; + } + + if (ebitmap_set_bit(&attr->types, datum->s.value - 1, TRUE)) { + yyerror("Out of memory"); + return -1; + } + } + + return 0; +} + +struct val_to_name { + unsigned int val; + char *name; +}; + +/* Adds a type, given by its textual name, to a typeset. If *add is + 0, then add the type to the negative set; otherwise if *add is 1 + then add it to the positive side. */ +static int set_types(type_set_t * set, char *id, int *add, char starallowed) +{ + type_datum_t *t; + + if (strcmp(id, "*") == 0) { + if (!starallowed) { + yyerror("* not allowed in this type of rule"); + return -1; + } + /* set TYPE_STAR flag */ + set->flags = TYPE_STAR; + free(id); + *add = 1; + return 0; + } + + if (strcmp(id, "~") == 0) { + if (!starallowed) { + yyerror("~ not allowed in this type of rule"); + return -1; + } + /* complement the set */ + set->flags = TYPE_COMP; + free(id); + *add = 1; + return 0; + } + + if (strcmp(id, "-") == 0) { + *add = 0; + free(id); + return 0; + } + + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + return -1; + } + t = hashtab_search(policydbp->p_types.table, id); + if (!t) { + yyerror2("unknown type %s", id); + free(id); + return -1; + } + + if (*add == 0) { + if (ebitmap_set_bit(&set->negset, t->s.value - 1, TRUE)) + goto oom; + } else { + if (ebitmap_set_bit(&set->types, t->s.value - 1, TRUE)) + goto oom; + } + free(id); + *add = 1; + return 0; + oom: + yyerror("Out of memory"); + free(id); + return -1; +} + +int define_compute_type_helper(int which, avrule_t ** rule) +{ + char *id; + type_datum_t *datum; + 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); + goto bad; + } + + ebitmap_for_each_bit(&tclasses, node, i) { + if (ebitmap_node_get_bit(node, i)) { + perm = malloc(sizeof(class_perm_node_t)); + if (!perm) { + yyerror("out of memory"); + 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?"); + free(id); + return -1; + } + + datum->state = (int)(bool_value[0] == 'T') ? 1 : 0; + return 0; + cleanup: + cond_destroy_bool(id, datum, NULL); + return -1; +} + +avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl) +{ + if (pass == 1) { + /* return something so we get through pass 1 */ + return (avrule_t *) 1; + } + + if (sl == NULL) { + /* This is a require block, return previous list */ + return avlist; + } + + /* prepend the new avlist to the pre-existing one */ + sl->next = avlist; + return sl; +} + +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); + 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) { + if (define_te_avtab_ioctl(avrule_template)) + return -1; + free(id); + } else { + yyerror("only ioctl extended permissions are supported"); + 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); + 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; + } + + 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, + "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); + goto bad; + } + + if (role->flavor != ROLE_ROLE) { + yyerror2("the new role %s must be a regular role", id); + goto bad; + } + + /* This ebitmap business is just to ensure that there are not conflicting role_trans rules */ + if (role_set_expand(&roles, &e_roles, policydbp, NULL, NULL)) + goto bad; + + if (type_set_expand(&types, &e_types, policydbp, 1)) + goto bad; + + ebitmap_for_each_bit(&e_roles, rnode, i) { + if (!ebitmap_node_get_bit(rnode, i)) + continue; + ebitmap_for_each_bit(&e_types, tnode, j) { + if (!ebitmap_node_get_bit(tnode, j)) + continue; + ebitmap_for_each_bit(&e_classes, cnode, k) { + if (!ebitmap_node_get_bit(cnode, k)) + continue; + for (tr = policydbp->role_tr; tr; + tr = tr->next) { + if (tr->role == (i + 1) && + tr->type == (j + 1) && + tr->tclass == (k + 1)) { + yyerror2("duplicate role " + "transition for " + "(%s,%s,%s)", + role_val_to_name(i+1), + policydbp->p_type_val_to_name[j], + policydbp->p_class_val_to_name[k]); + goto bad; + } + } + + tr = malloc(sizeof(struct role_trans)); + if (!tr) { + yyerror("out of memory"); + return -1; + } + memset(tr, 0, sizeof(struct role_trans)); + tr->role = i + 1; + tr->type = j + 1; + tr->tclass = k + 1; + tr->new_role = role->s.value; + tr->next = policydbp->role_tr; + policydbp->role_tr = tr; + } + } + } + /* Now add the real rule */ + rule = malloc(sizeof(struct role_trans_rule)); + if (!rule) { + yyerror("out of memory"); + return -1; + } + memset(rule, 0, sizeof(struct role_trans_rule)); + rule->roles = roles; + rule->types = types; + rule->classes = e_classes; + rule->new_role = role->s.value; + + append_role_trans(rule); + + ebitmap_destroy(&e_roles); + ebitmap_destroy(&e_types); + + return 0; + + bad: + return -1; +} + +int define_role_allow(void) +{ + char *id; + struct role_allow_rule *ra = 0; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + ra = malloc(sizeof(role_allow_rule_t)); + if (!ra) { + yyerror("out of memory"); + return -1; + } + role_allow_rule_init(ra); + + while ((id = queue_remove(id_queue))) { + if (set_roles(&ra->roles, id)) { + 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_rule_t *ftr; + type_datum_t *typdatum; + uint32_t otype; + unsigned int c, s, t; + int add; + + if (pass == 1) { + /* stype */ + while ((id = queue_remove(id_queue))) + free(id); + /* ttype */ + while ((id = queue_remove(id_queue))) + free(id); + /* tclass */ + while ((id = queue_remove(id_queue))) + free(id); + /* otype */ + id = queue_remove(id_queue); + free(id); + /* name */ + id = queue_remove(id_queue); + free(id); + return 0; + } + + + add = 1; + type_set_init(&stypes); + while ((id = queue_remove(id_queue))) { + if (set_types(&stypes, id, &add, 0)) + goto bad; + } + + add =1; + type_set_init(&ttypes); + while ((id = queue_remove(id_queue))) { + if (set_types(&ttypes, id, &add, 0)) + goto bad; + } + + ebitmap_init(&e_tclasses); + 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; + + for (ft = policydbp->filename_trans; ft; ft = ft->next) { + if (ft->stype == (s + 1) && + ft->ttype == (t + 1) && + ft->tclass == (c + 1) && + !strcmp(ft->name, name)) { + yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", + name, + policydbp->p_type_val_to_name[s], + policydbp->p_type_val_to_name[t], + policydbp->p_class_val_to_name[c]); + goto bad; + } + } + + ft = malloc(sizeof(*ft)); + if (!ft) { + yyerror("out of memory"); + goto bad; + } + memset(ft, 0, sizeof(*ft)); + + ft->next = policydbp->filename_trans; + policydbp->filename_trans = ft; + + ft->name = strdup(name); + if (!ft->name) { + yyerror("out of memory"); + goto bad; + } + ft->stype = s + 1; + ft->ttype = t + 1; + ft->tclass = c + 1; + ft->otype = otype; + } + } + + /* Now add the real rule since we didn't find any duplicates */ + ftr = malloc(sizeof(*ftr)); + if (!ftr) { + yyerror("out of memory"); + goto bad; + } + filename_trans_rule_init(ftr); + append_filename_trans(ftr); + + ftr->name = strdup(name); + 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() +{ + 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); + free(newc); + return -1; + } + + newc->u.port.protocol = protocol; + newc->u.port.low_port = low; + newc->u.port.high_port = high; + + if (low > high) { + yyerror2("low port %d exceeds high port %d", low, high); + free(newc); + return -1; + } + + if (parse_security_context(&newc->context[0])) { + free(newc); + return -1; + } + + /* Preserve the matching order specified in the configuration. */ + head = policydbp->ocontexts[OCON_PORT]; + for (l = NULL, c = head; c; l = c, c = c->next) { + unsigned int prot2, low2, high2; + + prot2 = c->u.port.protocol; + low2 = c->u.port.low_port; + high2 = c->u.port.high_port; + if (protocol != prot2) + continue; + if (low == low2 && high == high2) { + yyerror2("duplicate portcon entry for %s %d-%d ", id, + low, high); + goto bad; + } + if (low2 <= low && high2 >= high) { + yyerror2("portcon entry for %s %d-%d hidden by earlier " + "entry for %d-%d", id, low, high, low2, high2); + goto bad; + } + } + + if (l) + l->next = newc; + else + policydbp->ocontexts[OCON_PORT] = newc; + + return 0; + + bad: + free(newc); + return -1; +} + +int define_netif_context(void) +{ + ocontext_t *newc, *c, *head; + + if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { + yyerror("netifcon not supported for target"); + return -1; + } + + if (pass == 1) { + free(queue_remove(id_queue)); + parse_security_context(NULL); + parse_security_context(NULL); + return 0; + } + + newc = (ocontext_t *) malloc(sizeof(ocontext_t)); + if (!newc) { + yyerror("out of memory"); + return -1; + } + memset(newc, 0, sizeof(ocontext_t)); + + newc->u.name = (char *)queue_remove(id_queue); + if (!newc->u.name) { + free(newc); + return -1; + } + if (parse_security_context(&newc->context[0])) { + free(newc->u.name); + free(newc); + return -1; + } + if (parse_security_context(&newc->context[1])) { + context_destroy(&newc->context[0]); + free(newc->u.name); + free(newc); + return -1; + } + head = policydbp->ocontexts[OCON_NETIF]; + + for (c = head; c; c = c->next) { + if (!strcmp(newc->u.name, c->u.name)) { + yyerror2("duplicate entry for network interface %s", + newc->u.name); + context_destroy(&newc->context[0]); + context_destroy(&newc->context[1]); + free(newc->u.name); + free(newc); + return -1; + } + } + + newc->next = head; + policydbp->ocontexts[OCON_NETIF] = newc; + return 0; +} + +int define_ipv4_node_context() +{ + char *id; + int rc = 0; + struct in_addr addr, mask; + ocontext_t *newc, *c, *l, *head; + + if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { + yyerror("nodecon not supported for target"); + return -1; + } + + if (pass == 1) { + free(queue_remove(id_queue)); + free(queue_remove(id_queue)); + parse_security_context(NULL); + goto out; + } + + id = queue_remove(id_queue); + if (!id) { + yyerror("failed to read ipv4 address"); + rc = -1; + goto out; + } + + rc = inet_pton(AF_INET, id, &addr); + free(id); + if (rc < 1) { + yyerror("failed to parse ipv4 address"); + if (rc == 0) + rc = -1; + goto out; + } + + id = queue_remove(id_queue); + if (!id) { + yyerror("failed to read ipv4 address"); + rc = -1; + goto out; + } + + rc = inet_pton(AF_INET, id, &mask); + free(id); + if (rc < 1) { + yyerror("failed to parse ipv4 mask"); + if (rc == 0) + rc = -1; + goto out; + } + + newc = malloc(sizeof(ocontext_t)); + if (!newc) { + yyerror("out of memory"); + rc = -1; + goto out; + } + + memset(newc, 0, sizeof(ocontext_t)); + newc->u.node.addr = addr.s_addr; + newc->u.node.mask = mask.s_addr; + + if (parse_security_context(&newc->context[0])) { + free(newc); + return -1; + } + + /* Create order of most specific to least retaining + the order specified in the configuration. */ + head = policydbp->ocontexts[OCON_NODE]; + for (l = NULL, c = head; c; l = c, c = c->next) { + if (newc->u.node.mask > c->u.node.mask) + break; + } + + newc->next = c; + + if (l) + l->next = newc; + else + policydbp->ocontexts[OCON_NODE] = newc; + rc = 0; +out: + return rc; +} + +int define_ipv6_node_context(void) +{ + char *id; + int rc = 0; + struct in6_addr addr, mask; + ocontext_t *newc, *c, *l, *head; + + if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { + yyerror("nodecon not supported for target"); + return -1; + } + + if (pass == 1) { + free(queue_remove(id_queue)); + free(queue_remove(id_queue)); + parse_security_context(NULL); + goto out; + } + + id = queue_remove(id_queue); + if (!id) { + yyerror("failed to read ipv6 address"); + rc = -1; + goto out; + } + + rc = inet_pton(AF_INET6, id, &addr); + free(id); + if (rc < 1) { + yyerror("failed to parse ipv6 address"); + if (rc == 0) + rc = -1; + goto out; + } + + id = queue_remove(id_queue); + if (!id) { + yyerror("failed to read ipv6 address"); + rc = -1; + goto out; + } + + rc = inet_pton(AF_INET6, id, &mask); + free(id); + if (rc < 1) { + yyerror("failed to parse ipv6 mask"); + if (rc == 0) + rc = -1; + goto out; + } + + newc = malloc(sizeof(ocontext_t)); + if (!newc) { + yyerror("out of memory"); + rc = -1; + goto out; + } + + memset(newc, 0, sizeof(ocontext_t)); + +#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; + } + + newc = (ocontext_t *) malloc(sizeof(ocontext_t)); + if (!newc) { + yyerror("out of memory"); + return -1; + } + memset(newc, 0, sizeof(ocontext_t)); + + newc->u.name = (char *)queue_remove(id_queue); + if (!newc->u.name) + goto fail; + if (has_type) { + type = (char *)queue_remove(id_queue); + if (!type) + goto fail; + if (type[1] != 0) { + yyerror2("invalid type %s", type); + goto fail; + } + switch (type[0]) { + case 'b': + newc->v.sclass = SECCLASS_BLK_FILE; + break; + case 'c': + newc->v.sclass = SECCLASS_CHR_FILE; + break; + case 'd': + newc->v.sclass = SECCLASS_DIR; + break; + case 'p': + newc->v.sclass = SECCLASS_FIFO_FILE; + break; + case 'l': + newc->v.sclass = SECCLASS_LNK_FILE; + break; + case 's': + newc->v.sclass = SECCLASS_SOCK_FILE; + break; + case '-': + newc->v.sclass = SECCLASS_FILE; + break; + default: + yyerror2("invalid type %s", type); + goto fail; + } + } + if (parse_security_context(&newc->context[0])) + goto fail; + + head = genfs->head; + + for (p = NULL, c = head; c; p = c, c = c->next) { + if (!strcmp(newc->u.name, c->u.name) && + (!newc->v.sclass || !c->v.sclass + || newc->v.sclass == c->v.sclass)) { + yyerror2("duplicate entry for genfs entry (%s, %s)", + fstype, newc->u.name); + goto fail; + } + len = strlen(newc->u.name); + len2 = strlen(c->u.name); + if (len > len2) + break; + } + + newc->next = c; + if (p) + p->next = newc; + else + genfs->head = newc; + return 0; + fail: + if (type) + free(type); + context_destroy(&newc->context[0]); + if (fstype) + free(fstype); + if (newc->u.name) + free(newc->u.name); + free(newc); + return -1; +} + +int define_genfs_context(int has_type) +{ + return define_genfs_context_helper(queue_remove(id_queue), has_type); +} + +int define_range_trans(int class_specified) +{ + char *id; + level_datum_t *levdatum = 0; + class_datum_t *cladatum; + range_trans_rule_t *rule; + int l, add = 1; + + if (!mlspol) { + yyerror("range_transition rule in non-MLS configuration"); + return -1; + } + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + if (class_specified) + while ((id = queue_remove(id_queue))) + free(id); + id = queue_remove(id_queue); + free(id); + for (l = 0; l < 2; l++) { + while ((id = queue_remove(id_queue))) { + free(id); + } + id = queue_remove(id_queue); + if (!id) + break; + free(id); + } + return 0; + } + + rule = malloc(sizeof(struct range_trans_rule)); + if (!rule) { + yyerror("out of memory"); + return -1; + } + range_trans_rule_init(rule); + + while ((id = queue_remove(id_queue))) { + if (set_types(&rule->stypes, id, &add, 0)) + goto out; + } + add = 1; + while ((id = queue_remove(id_queue))) { + if (set_types(&rule->ttypes, id, &add, 0)) + goto out; + } + + if (class_specified) { + if (read_classes(&rule->tclasses)) + goto out; + } else { + cladatum = hashtab_search(policydbp->p_classes.table, + "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 */
diff --git a/selinux/checkpolicy/policy_define.h b/selinux/checkpolicy/policy_define.h new file mode 100644 index 0000000..964baae --- /dev/null +++ b/selinux/checkpolicy/policy_define.h
@@ -0,0 +1,74 @@ +/* Functions used to define policy grammar components. */ + +#ifndef _POLICY_DEFINE_H_ +#define _POLICY_DEFINE_H_ + +/* + * We need the following so we have a valid error return code in yacc + * when we have a parse error for a conditional rule. We can't check + * for NULL (ie 0) because that is a potentially valid return. + */ +#define COND_ERR ((avrule_t *)-1) +#define TRUE 1 +#define FALSE 0 + +avrule_t *define_cond_compute_type(int which); +avrule_t *define_cond_pol_list(avrule_t *avlist, avrule_t *stmt); +avrule_t *define_cond_te_avtab(int which); +avrule_t *define_cond_filename_trans(void); +cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2); +int define_attrib(void); +int define_attrib_role(void); +int define_av_perms(int inherits); +int define_bool_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_ */
diff --git a/selinux/checkpolicy/policy_parse.y b/selinux/checkpolicy/policy_parse.y new file mode 100644 index 0000000..3b6a2f8 --- /dev/null +++ b/selinux/checkpolicy/policy_parse.y
@@ -0,0 +1,949 @@ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: David Caplan, <dac@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@mentalrootkit.com> + * Jason Tang <jtang@tresys.com> + * + * Added support for binary policy modules + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * Copyright (C) 2003 - 2008 Tresys Technology, LLC + * Copyright (C) 2007 Red Hat Inc. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* FLASK */ + +%{ +#include <sys/types.h> +#include <assert.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> + +#include <sepol/policydb/expand.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/polcaps.h> +#include "queue.h" +#include "checkpolicy.h" +#include "module_compiler.h" +#include "policy_define.h" + +extern policydb_t *policydbp; +extern unsigned int pass; + +extern char yytext[]; +extern int yylex(void); +extern int yywarn(const char *msg); +extern int yyerror(const char *msg); + +typedef int (* require_func_t)(int pass); + +%} + +%union { + unsigned int val; + uint64_t val64; + uintptr_t valptr; + void *ptr; + require_func_t require_func; +} + +%type <ptr> cond_expr cond_expr_prim cond_pol_list cond_else +%type <ptr> cond_allow_def cond_auditallow_def cond_auditdeny_def cond_dontaudit_def +%type <ptr> cond_transition_def cond_te_avtab_def cond_rule_def +%type <ptr> role_def roles +%type <valptr> cexpr cexpr_prim op role_mls_op +%type <val> ipv4_addr_def number +%type <val64> number64 +%type <require_func> 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 + ; +sensitivity_def : SENSITIVITY identifier alias_def ';' + {if (define_sens()) return -1;} + | SENSITIVITY identifier ';' + {if (define_sens()) return -1;} + ; +alias_def : ALIAS names + ; +dominance : DOMINANCE identifier + {if (define_dominance()) return -1;} + | DOMINANCE '{' identifier_list '}' + {if (define_dominance()) return -1;} + ; +opt_categories : categories + | + ; +categories : category_def + | categories category_def + ; +category_def : CATEGORY identifier alias_def ';' + {if (define_category()) return -1;} + | CATEGORY identifier ';' + {if (define_category()) return -1;} + ; +levels : level_def + | levels level_def + ; +level_def : LEVEL identifier ':' id_comma_list ';' + {if (define_level()) return -1;} + | LEVEL identifier ';' + {if (define_level()) return -1;} + ; +mlspolicy : mlspolicy_decl + | mlspolicy mlspolicy_decl + ; +mlspolicy_decl : mlsconstraint_def + | mlsvalidatetrans_def + ; +mlsconstraint_def : MLSCONSTRAIN names names cexpr ';' + { if (define_constraint((constraint_expr_t*)$4)) return -1; } + ; +mlsvalidatetrans_def : MLSVALIDATETRANS names cexpr ';' + { if (define_validatetrans((constraint_expr_t*)$3)) return -1; } + ; +te_rbac : te_rbac_decl + | te_rbac te_rbac_decl + ; +te_rbac_decl : te_decl + | rbac_decl + | cond_stmt_def + | optional_block + | policycap_def + | ';' + ; +rbac_decl : attribute_role_def + | role_type_def + | role_dominance + | role_trans_def + | role_allow_def + | roleattribute_def + | role_attr_def + ; +te_decl : attribute_def + | type_def + | typealias_def + | typeattribute_def + | typebounds_def + | bool_def + | 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 + ; +pirq_context_def : PIRQCON number security_context_def + {if (define_pirq_context($2)) return -1;} + ; +iomem_context_def : IOMEMCON number64 security_context_def + {if (define_iomem_context($2,$2)) return -1;} + | IOMEMCON number64 '-' number64 security_context_def + {if (define_iomem_context($2,$4)) return -1;} + ; +ioport_context_def : IOPORTCON number security_context_def + {if (define_ioport_context($2,$2)) return -1;} + | IOPORTCON number '-' number security_context_def + {if (define_ioport_context($2,$4)) return -1;} + ; +pci_context_def : PCIDEVICECON number security_context_def + {if (define_pcidevice_context($2)) return -1;} + ; +dtree_context_def : DEVICETREECON path security_context_def + {if (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 ($<require_func>0 (pass)) return -1; } + | require_id_list ',' identifier + { if ($<require_func>0 (pass)) return -1; } + ; +optional_block : optional_decl '{' avrules_block '}' + { if (end_avrule_block(pass) == -1) return -1; } + optional_else + { if (end_optional(pass) == -1) return -1; } + ; +optional_else : else_decl '{' avrules_block '}' + { if (end_avrule_block(pass) == -1) return -1; } + | /* empty */ + ; +optional_decl : OPTIONAL + { if (begin_optional(pass) == -1) return -1; } + ; +else_decl : ELSE + { if (begin_optional_else(pass) == -1) return -1; } + ; +avrule_user_defs : user_def avrule_user_defs + | /* empty */ + ;
diff --git a/selinux/checkpolicy/policy_scan.l b/selinux/checkpolicy/policy_scan.l new file mode 100644 index 0000000..22da338 --- /dev/null +++ b/selinux/checkpolicy/policy_scan.l
@@ -0,0 +1,324 @@ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +/* Updated: David Caplan, <dac@tresys.com> + * + * Added conditional policy language extensions + * + * Jason Tang <jtang@tresys.com> + * + * Added support for binary policy modules + * + * Copyright (C) 2003-5 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* FLASK */ + +%{ +#include <sys/types.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> + +typedef int (* require_func_t)(void); + +#ifdef ANDROID +#include "policy_parse.h" +#else +#include "y.tab.h" +#endif + +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; +%} + +%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'; +}
diff --git a/selinux/checkpolicy/queue.c b/selinux/checkpolicy/queue.c new file mode 100644 index 0000000..272079c --- /dev/null +++ b/selinux/checkpolicy/queue.c
@@ -0,0 +1,180 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* FLASK */ + +/* + * Implementation of the double-ended queue type. + */ + +#include <stdlib.h> +#include "queue.h" + +queue_t queue_create(void) +{ + queue_t q; + + q = (queue_t) malloc(sizeof(struct queue_info)); + if (q == NULL) + return NULL; + + q->head = q->tail = NULL; + + return q; +} + +int queue_insert(queue_t q, queue_element_t e) +{ + queue_node_ptr_t newnode; + + if (!q) + return -1; + + newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node)); + if (newnode == NULL) + return -1; + + newnode->element = e; + newnode->next = NULL; + + if (q->head == NULL) { + q->head = q->tail = newnode; + } else { + q->tail->next = newnode; + q->tail = newnode; + } + + return 0; +} + +int queue_push(queue_t q, queue_element_t e) +{ + queue_node_ptr_t newnode; + + if (!q) + return -1; + + newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node)); + if (newnode == NULL) + return -1; + + newnode->element = e; + newnode->next = NULL; + + if (q->head == NULL) { + q->head = q->tail = newnode; + } else { + newnode->next = q->head; + q->head = newnode; + } + + return 0; +} + +queue_element_t queue_remove(queue_t q) +{ + queue_node_ptr_t node; + queue_element_t e; + + if (!q) + return NULL; + + if (q->head == NULL) + return NULL; + + node = q->head; + q->head = q->head->next; + if (q->head == NULL) + q->tail = NULL; + + e = node->element; + free(node); + + return e; +} + +queue_element_t queue_head(queue_t q) +{ + if (!q) + return NULL; + + if (q->head == NULL) + return NULL; + + return q->head->element; +} + +void queue_destroy(queue_t q) +{ + queue_node_ptr_t p, temp; + + if (!q) + return; + + p = q->head; + while (p != NULL) { + temp = p; + p = p->next; + free(temp); + } + + free(q); +} + +int queue_map(queue_t q, int (*f) (queue_element_t, void *), void *vp) +{ + queue_node_ptr_t p; + int ret; + + if (!q) + return 0; + + p = q->head; + while (p != NULL) { + ret = f(p->element, vp); + if (ret) + return ret; + p = p->next; + } + return 0; +} + +void queue_map_remove_on_error(queue_t q, + int (*f) (queue_element_t, void *), + void (*g) (queue_element_t, void *), void *vp) +{ + queue_node_ptr_t p, last, temp; + int ret; + + if (!q) + return; + + last = NULL; + p = q->head; + while (p != NULL) { + ret = f(p->element, vp); + if (ret) { + if (last) { + last->next = p->next; + if (last->next == NULL) + q->tail = last; + } else { + q->head = p->next; + if (q->head == NULL) + q->tail = NULL; + } + + temp = p; + p = p->next; + g(temp->element, vp); + free(temp); + } else { + last = p; + p = p->next; + } + } + + return; +} + +/* FLASK */
diff --git a/selinux/checkpolicy/queue.h b/selinux/checkpolicy/queue.h new file mode 100644 index 0000000..655c94b --- /dev/null +++ b/selinux/checkpolicy/queue.h
@@ -0,0 +1,62 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* FLASK */ + +/* + * A double-ended queue is a singly linked list of + * elements of arbitrary type that may be accessed + * at either end. + */ + +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +typedef void *queue_element_t; + +typedef struct queue_node *queue_node_ptr_t; + +typedef struct queue_node { + queue_element_t element; + queue_node_ptr_t next; +} queue_node_t; + +typedef struct queue_info { + queue_node_ptr_t head; + queue_node_ptr_t tail; +} queue_info_t; + +typedef queue_info_t *queue_t; + +queue_t queue_create(void); +int queue_insert(queue_t, queue_element_t); +int queue_push(queue_t, queue_element_t); +queue_element_t queue_remove(queue_t); +queue_element_t queue_head(queue_t); +void queue_destroy(queue_t); + +/* + Applies the specified function f to each element in the + specified queue. + + In addition to passing the element to f, queue_map + passes the specified void* pointer to f on each invocation. + + If f returns a non-zero status, then queue_map will cease + iterating through the hash table and will propagate the error + return to its caller. + */ +int queue_map(queue_t, int (*f) (queue_element_t, void *), void *); + +/* + Same as queue_map, except that if f returns a non-zero status, + then the element will be removed from the queue and the g + function will be applied to the element. + */ +void queue_map_remove_on_error(queue_t, + int (*f) (queue_element_t, void *), + void (*g) (queue_element_t, void *), void *); + +#endif + +/* FLASK */
diff --git a/selinux/checkpolicy/test/Makefile b/selinux/checkpolicy/test/Makefile new file mode 100644 index 0000000..c2367e1 --- /dev/null +++ b/selinux/checkpolicy/test/Makefile
@@ -0,0 +1,21 @@ +# +# Makefile for building the dispol program +# +PREFIX ?= $(DESTDIR)/usr +BINDIR=$(PREFIX)/bin +LIBDIR ?= $(PREFIX)/lib +INCLUDEDIR ?= $(PREFIX)/include + +CFLAGS ?= -g -Wall -W -Werror -O2 -pipe +override CFLAGS += -I$(INCLUDEDIR) + +LDLIBS=-lfl $(LIBDIR)/libsepol.a -L$(LIBDIR) + +all: dispol dismod + +dispol: dispol.o + +dismod: dismod.o + +clean: + -rm -f dispol dismod *.o
diff --git a/selinux/checkpolicy/test/dismod.c b/selinux/checkpolicy/test/dismod.c new file mode 100644 index 0000000..08b039d --- /dev/null +++ b/selinux/checkpolicy/test/dismod.c
@@ -0,0 +1,1003 @@ + +/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * Copyright (C) 2003,2004,2005 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* + * dismod.c + * + * Test program to the contents of a binary policy in text + * form. + * + * dismod binary_mod_file + */ + +#include <getopt.h> +#include <assert.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/module.h> +#include <sepol/policydb/util.h> +#include <sepol/policydb/polcaps.h> + +#include <byteswap.h> +#include <endian.h> + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le32_to_cpu(x) (x) +#else +#define le32_to_cpu(x) bswap_32(x) +#endif + +#define DISPLAY_AVBLOCK_COND_AVTAB 0 +#define DISPLAY_AVBLOCK_UNCOND_AVTAB 1 +#define DISPLAY_AVBLOCK_ROLE_TYPE_NODE 2 /* unused? */ +#define DISPLAY_AVBLOCK_ROLE_TRANS 3 +#define DISPLAY_AVBLOCK_ROLE_ALLOW 4 +#define DISPLAY_AVBLOCK_REQUIRES 5 +#define DISPLAY_AVBLOCK_DECLARES 6 +#define DISPLAY_AVBLOCK_FILENAME_TRANS 7 + +static policydb_t policydb; +extern unsigned int ss_initialized; + +int policyvers = MOD_POLICYDB_VERSION_BASE; + +static const char *symbol_labels[9] = { + "commons", + "classes", "roles ", "types ", "users ", "bools ", + "levels ", "cats ", "attribs" +}; + +void usage(const char *progname) +{ + printf("usage: %s binary_pol_file\n\n", progname); + exit(1); +} + +static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p, + FILE * fp) +{ + char *perm; + fprintf(fp, "{"); + perm = sepol_av_to_string(p, class, mask); + if (perm) + fprintf(fp, "%s ", perm); + fprintf(fp, "}"); +} + +static void render_access_bitmap(ebitmap_t * map, uint32_t class, + policydb_t * p, FILE * fp) +{ + unsigned int i; + char *perm; + fprintf(fp, "{"); + for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) { + if (ebitmap_get_bit(map, i)) { + perm = sepol_av_to_string(p, class, 1 << i); + if (perm) + fprintf(fp, " %s", perm); + } + } + fprintf(fp, " }"); +} + +static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type, + uint32_t symbol_value, const char *prefix) +{ + char *id = p->sym_val_to_name[symbol_type][symbol_value]; + scope_datum_t *scope = + (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id); + assert(scope != NULL); + if (scope->scope == SCOPE_REQ) { + fprintf(fp, " [%s%s]", prefix, id); + } else { + fprintf(fp, " %s%s", prefix, id); + } +} + +int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy, + FILE * fp) +{ + unsigned int i, num_types; + + if (set->flags & TYPE_STAR) { + fprintf(fp, " * "); + return 0; + } else if (set->flags & TYPE_COMP) { + fprintf(fp, " ~"); + } + + num_types = 0; + if (flags & RULE_SELF) { + num_types++; + } + + for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); + i++) { + if (!ebitmap_get_bit(&set->types, i)) + continue; + num_types++; + if (num_types > 1) + break; + } + + if (num_types <= 1) { + for (i = ebitmap_startbit(&set->negset); + i < ebitmap_length(&set->negset); i++) { + if (!ebitmap_get_bit(&set->negset, i)) + continue; + num_types++; + if (num_types > 1) + break; + } + } + + if (num_types > 1) + fprintf(fp, "{"); + + for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); + i++) { + if (!ebitmap_get_bit(&set->types, i)) + continue; + display_id(policy, fp, SYM_TYPES, i, ""); + } + + for (i = ebitmap_startbit(&set->negset); + i < ebitmap_length(&set->negset); i++) { + if (!ebitmap_get_bit(&set->negset, i)) + continue; + display_id(policy, fp, SYM_TYPES, i, "-"); + } + + if (flags & RULE_SELF) { + fprintf(fp, " self"); + } + + if (num_types > 1) + fprintf(fp, " }"); + + return 0; +} + +int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp) +{ + unsigned int i, num = 0; + + if (roles->flags & ROLE_STAR) { + fprintf(fp, " * "); + return 0; + } else if (roles->flags & ROLE_COMP) { + fprintf(fp, " ~"); + } + + for (i = ebitmap_startbit(&roles->roles); + i < ebitmap_length(&roles->roles); i++) { + if (!ebitmap_get_bit(&roles->roles, i)) + continue; + num++; + if (num > 1) { + fprintf(fp, "{"); + break; + } + } + + for (i = ebitmap_startbit(&roles->roles); + i < ebitmap_length(&roles->roles); i++) { + if (ebitmap_get_bit(&roles->roles, i)) + display_id(p, fp, SYM_ROLES, i, ""); + } + + if (num > 1) + fprintf(fp, " }"); + + return 0; + +} + +int display_avrule(avrule_t * avrule, policydb_t * policy, + FILE * fp) +{ + class_perm_node_t *cur; + int num_classes; + + if (avrule == NULL) { + fprintf(fp, " <empty>\n"); + return 0; + } + if (avrule->specified & AVRULE_AV) { + if (avrule->specified & AVRULE_ALLOWED) { + fprintf(fp, " allow"); + } + if (avrule->specified & AVRULE_AUDITALLOW) { + fprintf(fp, " auditallow "); + } + if (avrule->specified & AVRULE_DONTAUDIT) { + fprintf(fp, " dontaudit"); + } + } else if (avrule->specified & AVRULE_TYPE) { + if (avrule->specified & AVRULE_TRANSITION) { + fprintf(fp, " type_transition"); + } + if (avrule->specified & AVRULE_MEMBER) { + fprintf(fp, " type_member"); + } + if (avrule->specified & AVRULE_CHANGE) { + fprintf(fp, " type_change"); + } + } else if (avrule->specified & AVRULE_NEVERALLOW) { + fprintf(fp, " neverallow"); + } else { + fprintf(fp, " ERROR: no valid rule type specified\n"); + return -1; + } + + if (display_type_set(&avrule->stypes, 0, policy, fp)) + return -1; + + if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp)) + return -1; + + fprintf(fp, " :"); + cur = avrule->perms; + num_classes = 0; + while (cur) { + num_classes++; + if (num_classes > 1) + break; + cur = cur->next; + } + + if (num_classes > 1) + fprintf(fp, " {"); + + cur = avrule->perms; + while (cur) { + display_id(policy, fp, SYM_CLASSES, cur->tclass - 1, ""); + cur = cur->next; + } + + if (num_classes > 1) + fprintf(fp, " }"); + fprintf(fp, " "); + + if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) { + render_access_mask(avrule->perms->data, avrule->perms->tclass, + policy, fp); + } else if (avrule->specified & AVRULE_TYPE) { + display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); + } + + fprintf(fp, ";\n"); + + return 0; +} + +int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) +{ + type_datum_t *type; + FILE *fp; + unsigned int i, first_attrib = 1; + + type = (type_datum_t *) datum; + fp = (FILE *) data; + + if (type->primary) { + display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); + fprintf(fp, " [%d]: ", type->s.value); + } else { + /* as that aliases have no value of their own and that + * they can never be required by a module, use this + * alternative way of displaying a name */ + fprintf(fp, " %s [%d]: ", (char *)key, type->s.value); + } + if (type->flavor == TYPE_ATTRIB) { + fprintf(fp, "attribute for types"); + for (i = ebitmap_startbit(&type->types); + i < ebitmap_length(&type->types); i++) { + if (!ebitmap_get_bit(&type->types, i)) + continue; + if (first_attrib) { + first_attrib = 0; + } else { + fprintf(fp, ","); + } + display_id(&policydb, fp, SYM_TYPES, i, ""); + } + } else if (type->primary) { + fprintf(fp, "type"); + } else { + fprintf(fp, "alias for type"); + display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); + } + fprintf(fp, " flags:%x\n", type->flags); + + return 0; +} + +int display_types(policydb_t * p, FILE * fp) +{ + if (hashtab_map(p->p_types.table, display_type_callback, fp)) + return -1; + return 0; +} + +int display_users(policydb_t * p, FILE * fp) +{ + unsigned int i, j; + ebitmap_t *bitmap; + for (i = 0; i < p->p_users.nprim; i++) { + display_id(p, fp, SYM_USERS, i, ""); + fprintf(fp, ":"); + bitmap = &(p->user_val_to_struct[i]->roles.roles); + for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap); + j++) { + if (ebitmap_get_bit(bitmap, j)) { + display_id(p, fp, SYM_ROLES, j, ""); + } + } + fprintf(fp, "\n"); + } + return 0; +} + +int display_bools(policydb_t * p, FILE * fp) +{ + unsigned int i; + + for (i = 0; i < p->p_bools.nprim; i++) { + display_id(p, fp, SYM_BOOLS, i, ""); + fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state); + } + return 0; +} + +void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) +{ + + cond_expr_t *cur; + for (cur = exp; cur != NULL; cur = cur->next) { + switch (cur->expr_type) { + case COND_BOOL: + fprintf(fp, "%s ", + p->p_bool_val_to_name[cur->bool - 1]); + break; + case COND_NOT: + fprintf(fp, "! "); + break; + case COND_OR: + fprintf(fp, "|| "); + break; + case COND_AND: + fprintf(fp, "&& "); + break; + case COND_XOR: + fprintf(fp, "^ "); + break; + case COND_EQ: + fprintf(fp, "== "); + break; + case COND_NEQ: + fprintf(fp, "!= "); + break; + default: + fprintf(fp, "error!"); + break; + } + } +} + +void display_policycon(FILE * fp) +{ + /* There was an attempt to implement this at one time. Look through + * git history to find it. */ + fprintf(fp, "Sorry, not implemented\n"); +} + +void display_initial_sids(policydb_t * p, FILE * fp) +{ + ocontext_t *cur; + char *user, *role, *type; + + fprintf(fp, "Initial SIDs:\n"); + for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) { + user = p->p_user_val_to_name[cur->context[0].user - 1]; + role = p->p_role_val_to_name[cur->context[0].role - 1]; + type = p->p_type_val_to_name[cur->context[0].type - 1]; + fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", + cur->u.name, cur->sid[0], user, role, type); + } +#if 0 + fprintf(fp, "Policy Initial SIDs:\n"); + for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) { + user = p->p_user_val_to_name[cur->context[0].user - 1]; + role = p->p_role_val_to_name[cur->context[0].role - 1]; + type = p->p_type_val_to_name[cur->context[0].type - 1]; + fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", + cur->u.name, cur->sid[0], user, role, type); + } +#endif +} + +void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp) +{ + unsigned int i, num = 0; + + for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { + if (!ebitmap_get_bit(classes, i)) + continue; + num++; + if (num > 1) { + fprintf(fp, "{"); + break; + } + } + + for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { + if (ebitmap_get_bit(classes, i)) + display_id(p, fp, SYM_CLASSES, i, ""); + } + + if (num > 1) + fprintf(fp, " }"); +} + +void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp) +{ + for (; tr; tr = tr->next) { + fprintf(fp, "role transition "); + display_mod_role_set(&tr->roles, p, fp); + display_type_set(&tr->types, 0, p, fp); + fprintf(fp, " :"); + display_class_set(&tr->classes, p, fp); + display_id(p, fp, SYM_ROLES, tr->new_role - 1, ""); + fprintf(fp, "\n"); + } +} + +void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp) +{ + for (; ra; ra = ra->next) { + fprintf(fp, "role allow "); + display_mod_role_set(&ra->roles, p, fp); + display_mod_role_set(&ra->new_roles, p, fp); + fprintf(fp, "\n"); + } +} + +static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp) +{ + fprintf(fp, "filename transition"); + for (; tr; tr = tr->next) { + display_type_set(&tr->stypes, 0, p, fp); + display_type_set(&tr->ttypes, 0, p, fp); + display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":"); + display_id(p, fp, SYM_TYPES, tr->otype - 1, ""); + fprintf(fp, " %s\n", tr->name); + } +} + +int role_display_callback(hashtab_key_t key __attribute__((unused)), + hashtab_datum_t datum, void *data) +{ + role_datum_t *role; + FILE *fp; + + role = (role_datum_t *) datum; + fp = (FILE *) data; + + fprintf(fp, "role:"); + display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, ""); + fprintf(fp, " types: "); + display_type_set(&role->types, 0, &policydb, fp); + fprintf(fp, "\n"); + + return 0; +} + +static int display_scope_index(scope_index_t * indices, policydb_t * p, + FILE * out_fp) +{ + unsigned int i; + for (i = 0; i < SYM_NUM; i++) { + unsigned int any_found = 0, j; + fprintf(out_fp, "%s:", symbol_labels[i]); + for (j = ebitmap_startbit(&indices->scope[i]); + j < ebitmap_length(&indices->scope[i]); j++) { + if (ebitmap_get_bit(&indices->scope[i], j)) { + any_found = 1; + fprintf(out_fp, " %s", + p->sym_val_to_name[i][j]); + if (i == SYM_CLASSES) { + if (j < indices->class_perms_len) { + render_access_bitmap(indices-> + class_perms_map + + j, j + 1, + p, out_fp); + } else { + fprintf(out_fp, + "<no perms known>"); + } + } + } + } + if (!any_found) { + fprintf(out_fp, " <empty>"); + } + fprintf(out_fp, "\n"); + } + return 0; +} + +#if 0 +int display_cond_expressions(policydb_t * p, FILE * fp) +{ + cond_node_t *cur; + cond_av_list_t *av_cur; + for (cur = p->cond_list; cur != NULL; cur = cur->next) { + fprintf(fp, "expression: "); + display_expr(p, cur->expr, fp); + fprintf(fp, "current state: %d\n", cur->cur_state); + fprintf(fp, "True list:\n"); + for (av_cur = cur->true_list; av_cur != NULL; + av_cur = av_cur->next) { + fprintf(fp, "\t"); + render_av_rule(&av_cur->node->key, &av_cur->node->datum, + RENDER_CONDITIONAL, p, fp); + } + fprintf(fp, "False list:\n"); + for (av_cur = cur->false_list; av_cur != NULL; + av_cur = av_cur->next) { + fprintf(fp, "\t"); + render_av_rule(&av_cur->node->key, &av_cur->node->datum, + RENDER_CONDITIONAL, p, fp); + } + } + return 0; +} + +int change_bool(char *name, int state, policydb_t * p, FILE * fp) +{ + cond_bool_datum_t *bool; + + bool = hashtab_search(p->p_bools.table, name); + if (bool == NULL) { + fprintf(fp, "Could not find bool %s\n", name); + return -1; + } + bool->state = state; + evaluate_conds(p); + return 0; +} +#endif + +int display_avdecl(avrule_decl_t * decl, int field, + policydb_t * policy, FILE * out_fp) +{ + fprintf(out_fp, "decl %u:%s\n", decl->decl_id, + (decl->enabled ? " [enabled]" : "")); + switch (field) { + case DISPLAY_AVBLOCK_COND_AVTAB:{ + cond_list_t *cond = decl->cond_list; + avrule_t *avrule; + while (cond) { + fprintf(out_fp, "expression: "); + display_expr(&policydb, cond->expr, out_fp); + fprintf(out_fp, "current state: %d\n", + cond->cur_state); + fprintf(out_fp, "True list:\n"); + avrule = cond->avtrue_list; + while (avrule) { + display_avrule(avrule, + &policydb, out_fp); + avrule = avrule->next; + } + fprintf(out_fp, "False list:\n"); + avrule = cond->avfalse_list; + while (avrule) { + display_avrule(avrule, + &policydb, out_fp); + avrule = avrule->next; + } + cond = cond->next; + } + break; + } + case DISPLAY_AVBLOCK_UNCOND_AVTAB:{ + avrule_t *avrule = decl->avrules; + if (avrule == NULL) { + fprintf(out_fp, " <empty>\n"); + } + while (avrule != NULL) { + if (display_avrule(avrule, policy, out_fp)) + return -1; + avrule = avrule->next; + } + break; + } + case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{ /* role_type_node */ + break; + } + case DISPLAY_AVBLOCK_ROLE_TRANS:{ + display_role_trans(decl->role_tr_rules, policy, out_fp); + break; + } + case DISPLAY_AVBLOCK_ROLE_ALLOW:{ + display_role_allow(decl->role_allow_rules, policy, + out_fp); + break; + } + case DISPLAY_AVBLOCK_REQUIRES:{ + if (display_scope_index + (&decl->required, policy, out_fp)) { + return -1; + } + break; + } + case DISPLAY_AVBLOCK_DECLARES:{ + if (display_scope_index + (&decl->declared, policy, out_fp)) { + return -1; + } + break; + } + case DISPLAY_AVBLOCK_FILENAME_TRANS: + display_filename_trans(decl->filename_trans_rules, policy, + out_fp); + break; + default:{ + assert(0); + } + } + return 0; /* should never get here */ +} + +int display_avblock(int field, policydb_t * policy, + FILE * out_fp) +{ + avrule_block_t *block = policydb.global; + while (block != NULL) { + fprintf(out_fp, "--- begin avrule block ---\n"); + avrule_decl_t *decl = block->branch_list; + while (decl != NULL) { + if (display_avdecl(decl, field, policy, out_fp)) { + return -1; + } + decl = decl->next; + } + block = block->next; + } + return 0; +} + +int display_handle_unknown(policydb_t * p, FILE * out_fp) +{ + if (p->handle_unknown == ALLOW_UNKNOWN) + fprintf(out_fp, "Allow unknown classes and perms\n"); + else if (p->handle_unknown == DENY_UNKNOWN) + fprintf(out_fp, "Deny unknown classes and perms\n"); + else if (p->handle_unknown == REJECT_UNKNOWN) + fprintf(out_fp, "Reject unknown classes and perms\n"); + return 0; +} + +static int read_policy(char *filename, policydb_t * policy) +{ + FILE *in_fp; + struct policy_file f; + int retval; + uint32_t buf[1]; + + if ((in_fp = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "Can't open '%s': %s\n", + filename, strerror(errno)); + exit(1); + } + policy_file_init(&f); + f.type = PF_USE_STDIO; + f.fp = in_fp; + + /* peek at the first byte. if they are indicative of a + package use the package reader, otherwise use the normal + policy reader */ + if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) { + fprintf(stderr, "Could not read from policy.\n"); + exit(1); + } + rewind(in_fp); + if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) { + sepol_module_package_t *package; + if (sepol_module_package_create(&package)) { + fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); + exit(1); + } + package->policy = (sepol_policydb_t *) policy; + package->file_contexts = NULL; + retval = + sepol_module_package_read(package, + (sepol_policy_file_t *) & f, 1); + free(package->file_contexts); + } else { + if (policydb_init(policy)) { + fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); + exit(1); + } + retval = policydb_read(policy, &f, 1); + } + fclose(in_fp); + return retval; +} + +static void link_module(policydb_t * base, FILE * out_fp) +{ + char module_name[80] = { 0 }; + int ret; + policydb_t module, *mods = &module; + + if (base->policy_type != POLICY_BASE) { + printf("Can only link if initial file was a base policy.\n"); + return; + } + printf("\nModule filename: "); + if (fgets(module_name, sizeof(module_name), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + exit(1); + } + + module_name[strlen(module_name) - 1] = '\0'; /* remove LF */ + if (module_name[0] == '\0') { + return; + } + + /* read the binary policy */ + fprintf(out_fp, "Reading module...\n"); + if (read_policy(module_name, mods)) { + fprintf(stderr, + "%s: error(s) encountered while loading policy\n", + module_name); + exit(1); + } + if (module.policy_type != POLICY_MOD) { + fprintf(stderr, "This file is not a loadable policy module.\n"); + exit(1); + } + if (policydb_index_classes(&module) || + policydb_index_others(NULL, &module, 0)) { + fprintf(stderr, "Could not index module.\n"); + exit(1); + } + ret = link_modules(NULL, base, &mods, 1, 0); + if (ret != 0) { + printf("Link failed (error %d)\n", ret); + printf("(You will probably need to restart dismod.)\n"); + } + policydb_destroy(&module); + return; +} + +static void display_policycaps(policydb_t * p, FILE * fp) +{ + ebitmap_node_t *node; + const char *capname; + char buf[64]; + unsigned int i; + + fprintf(fp, "policy capabilities:\n"); + ebitmap_for_each_bit(&p->policycaps, node, i) { + if (ebitmap_node_get_bit(node, i)) { + capname = sepol_polcap_getname(i); + if (capname == NULL) { + snprintf(buf, sizeof(buf), "unknown (%d)", i); + capname = buf; + } + fprintf(fp, "\t%s\n", capname); + } + } +} + +int menu(void) +{ + printf("\nSelect a command:\n"); + printf("1) display unconditional AVTAB\n"); + printf("2) display conditional AVTAB\n"); + printf("3) display users\n"); + printf("4) display bools\n"); + printf("5) display roles\n"); + printf("6) display types, attributes, and aliases\n"); + printf("7) display role transitions\n"); + printf("8) display role allows\n"); + printf("9) Display policycon\n"); + printf("0) Display initial SIDs\n"); + printf("\n"); + printf("a) Display avrule requirements\n"); + printf("b) Display avrule declarations\n"); + printf("c) Display policy capabilities\n"); + printf("l) Link in a module\n"); + printf("u) Display the unknown handling setting\n"); + printf("F) Display filename_trans rules\n"); + printf("\n"); + printf("f) set output file\n"); + printf("m) display menu\n"); + printf("q) quit\n"); + return 0; +} + +int main(int argc, char **argv) +{ + FILE *out_fp = stdout; + char ans[81], OutfileName[121]; + + if (argc != 2) + usage(argv[0]); + + /* read the binary policy */ + fprintf(out_fp, "Reading policy...\n"); + if (policydb_init(&policydb)) { + fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); + exit(1); + } + if (read_policy(argv[1], &policydb)) { + fprintf(stderr, + "%s: error(s) encountered while loading policy\n", + argv[0]); + exit(1); + } + + if (policydb.policy_type != POLICY_BASE && + policydb.policy_type != POLICY_MOD) { + fprintf(stderr, + "This file is neither a base nor loadable policy module.\n"); + exit(1); + } + + if (policydb_index_classes(&policydb)) { + fprintf(stderr, "Error indexing classes\n"); + exit(1); + } + + if (policydb_index_others(NULL, &policydb, 1)) { + fprintf(stderr, "Error indexing others\n"); + exit(1); + } + + if (policydb.policy_type == POLICY_BASE) { + printf("Binary base policy file loaded.\n\n"); + } else { + printf("Binary policy module file loaded.\n"); + printf("Module name: %s\n", policydb.name); + printf("Module version: %s\n", policydb.version); + printf("\n"); + } + + menu(); + for (;;) { + printf("\nCommand (\'m\' for menu): "); + if (fgets(ans, sizeof(ans), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + continue; + } + + switch (ans[0]) { + + case '1': + fprintf(out_fp, "unconditional avtab:\n"); + display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB, + &policydb, out_fp); + break; + case '2': + fprintf(out_fp, "conditional avtab:\n"); + display_avblock(DISPLAY_AVBLOCK_COND_AVTAB, + &policydb, out_fp); + break; + case '3': + display_users(&policydb, out_fp); + break; + case '4': + display_bools(&policydb, out_fp); + break; + case '5': + if (hashtab_map + (policydb.p_roles.table, role_display_callback, + out_fp)) + exit(1); + break; + case '6': + if (display_types(&policydb, out_fp)) { + fprintf(stderr, "Error displaying types\n"); + exit(1); + } + break; + case '7': + fprintf(out_fp, "role transitions:\n"); + display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS, + &policydb, out_fp); + break; + case '8': + fprintf(out_fp, "role allows:\n"); + display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW, + &policydb, out_fp); + break; + case '9': + display_policycon(out_fp); + break; + case '0': + display_initial_sids(&policydb, out_fp); + break; + case 'a': + fprintf(out_fp, "avrule block requirements:\n"); + display_avblock(DISPLAY_AVBLOCK_REQUIRES, + &policydb, out_fp); + break; + case 'b': + fprintf(out_fp, "avrule block declarations:\n"); + display_avblock(DISPLAY_AVBLOCK_DECLARES, + &policydb, out_fp); + break; + case 'c': + display_policycaps(&policydb, out_fp); + break; + case 'u': + case 'U': + display_handle_unknown(&policydb, out_fp); + break; + case 'f': + printf + ("\nFilename for output (<CR> for screen output): "); + if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + break; + } + OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ + if (strlen(OutfileName) == 0) + out_fp = stdout; + else if ((out_fp = fopen(OutfileName, "w")) == NULL) { + fprintf(stderr, "Cannot open output file %s\n", + OutfileName); + out_fp = stdout; + } + if (out_fp != stdout) + printf("\nOutput to file: %s\n", OutfileName); + break; + case 'F': + fprintf(out_fp, "filename_trans rules:\n"); + display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS, + &policydb, out_fp); + break; + case 'l': + link_module(&policydb, out_fp); + break; + case 'q': + policydb_destroy(&policydb); + exit(0); + break; + case 'm': + menu(); + break; + default: + printf("\nInvalid choice\n"); + menu(); + break; + + } + } + exit(EXIT_SUCCESS); +}
diff --git a/selinux/checkpolicy/test/dispol.c b/selinux/checkpolicy/test/dispol.c new file mode 100644 index 0000000..86f5688 --- /dev/null +++ b/selinux/checkpolicy/test/dispol.c
@@ -0,0 +1,539 @@ + +/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * Copyright (C) 2003 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* + * displaypol.c + * + * Test program to the contents of a binary policy in text + * form. This program currently only displays the + * avtab (including conditional avtab) rules. + * + * displaypol binary_pol_file + */ + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/avtab.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/util.h> +#include <sepol/policydb/polcaps.h> +#include <getopt.h> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> + +static policydb_t policydb; + +void usage(const char *progname) +{ + printf("usage: %s binary_pol_file\n\n", progname); + exit(1); +} + +int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p, + FILE * fp) +{ + char *perm; + fprintf(fp, "{"); + perm = sepol_av_to_string(p, key->target_class, mask); + if (perm) + fprintf(fp, "%s ", perm); + fprintf(fp, "}"); + return 0; +} + +int render_type(uint32_t type, policydb_t * p, FILE * fp) +{ + fprintf(fp, "%s", p->p_type_val_to_name[type - 1]); + return 0; +} + +int render_key(avtab_key_t * key, policydb_t * p, FILE * fp) +{ + char *stype, *ttype, *tclass; + stype = p->p_type_val_to_name[key->source_type - 1]; + ttype = p->p_type_val_to_name[key->target_type - 1]; + tclass = p->p_class_val_to_name[key->target_class - 1]; + if (stype && ttype) + fprintf(fp, "%s %s : %s ", stype, ttype, tclass); + else if (stype) + fprintf(fp, "%s %u : %s ", stype, key->target_type, tclass); + else if (ttype) + fprintf(fp, "%u %s : %s ", key->source_type, ttype, tclass); + else + fprintf(fp, "%u %u : %s ", key->source_type, key->target_type, + tclass); + return 0; +} + +/* 'what' values for this function */ +#define RENDER_UNCONDITIONAL 0x0001 /* render all regardless of enabled state */ +#define RENDER_ENABLED 0x0002 +#define RENDER_DISABLED 0x0004 +#define RENDER_CONDITIONAL (RENDER_ENABLED|RENDER_DISABLED) + +int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what, + policydb_t * p, FILE * fp) +{ + if (!(what & RENDER_UNCONDITIONAL)) { + if (what != RENDER_CONDITIONAL && (((what & RENDER_ENABLED) + && !(key-> + specified & + AVTAB_ENABLED)) + || ((what & RENDER_DISABLED) + && (key-> + specified & + AVTAB_ENABLED)))) { + return 0; /* doesn't match selection criteria */ + } + } + + if (!(what & RENDER_UNCONDITIONAL)) { + if (key->specified & AVTAB_ENABLED) + fprintf(fp, "[enabled] "); + else if (!(key->specified & AVTAB_ENABLED)) + fprintf(fp, "[disabled] "); + } + + if (key->specified & AVTAB_AV) { + if (key->specified & AVTAB_ALLOWED) { + fprintf(fp, "allow "); + render_key(key, p, fp); + render_access_mask(datum->data, key, p, fp); + fprintf(fp, ";\n"); + } + if (key->specified & AVTAB_AUDITALLOW) { + fprintf(fp, "auditallow "); + render_key(key, p, fp); + render_access_mask(datum->data, key, p, fp); + fprintf(fp, ";\n"); + } + if (key->specified & AVTAB_AUDITDENY) { + fprintf(fp, "dontaudit "); + render_key(key, p, fp); + /* We inverse the mask for dontaudit since the mask is internally stored + * as a auditdeny mask */ + render_access_mask(~datum->data, key, p, fp); + fprintf(fp, ";\n"); + } + } else if (key->specified & AVTAB_TYPE) { + if (key->specified & AVTAB_TRANSITION) { + fprintf(fp, "type_transition "); + render_key(key, p, fp); + render_type(datum->data, p, fp); + fprintf(fp, ";\n"); + } + if (key->specified & AVTAB_MEMBER) { + fprintf(fp, "type_member "); + render_key(key, p, fp); + render_type(datum->data, p, fp); + fprintf(fp, ";\n"); + } + if (key->specified & AVTAB_CHANGE) { + fprintf(fp, "type_change "); + render_key(key, p, fp); + render_type(datum->data, p, fp); + fprintf(fp, ";\n"); + } + } else if (key->specified & AVTAB_XPERMS) { + if (key->specified & AVTAB_XPERMS_ALLOWED) + fprintf(fp, "allowxperm "); + else if (key->specified & AVTAB_XPERMS_AUDITALLOW) + fprintf(fp, "auditallowxperm "); + else if (key->specified & AVTAB_XPERMS_DONTAUDIT) + fprintf(fp, "dontauditxperm "); + render_key(key, p, fp); + fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms)); + } else { + fprintf(fp, " ERROR: no valid rule type specified\n"); + return -1; + } + return 0; +} + +int display_avtab(avtab_t * a, uint32_t what, policydb_t * p, FILE * fp) +{ + unsigned int i; + avtab_ptr_t cur; + + /* hmm...should have used avtab_map. */ + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + render_av_rule(&cur->key, &cur->datum, what, p, fp); + } + } + fprintf(fp, "\n"); + return 0; +} + +int display_bools(policydb_t * p, FILE * fp) +{ + unsigned int i; + + for (i = 0; i < p->p_bools.nprim; i++) { + fprintf(fp, "%s : %d\n", p->p_bool_val_to_name[i], + p->bool_val_to_struct[i]->state); + } + return 0; +} + +void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) +{ + + cond_expr_t *cur; + for (cur = exp; cur != NULL; cur = cur->next) { + switch (cur->expr_type) { + case COND_BOOL: + fprintf(fp, "%s ", + p->p_bool_val_to_name[cur->bool - 1]); + break; + case COND_NOT: + fprintf(fp, "! "); + break; + case COND_OR: + fprintf(fp, "|| "); + break; + case COND_AND: + fprintf(fp, "&& "); + break; + case COND_XOR: + fprintf(fp, "^ "); + break; + case COND_EQ: + fprintf(fp, "== "); + break; + case COND_NEQ: + fprintf(fp, "!= "); + break; + default: + fprintf(fp, "error!"); + break; + } + } +} + +int display_cond_expressions(policydb_t * p, FILE * fp) +{ + cond_node_t *cur; + cond_av_list_t *av_cur; + + for (cur = p->cond_list; cur != NULL; cur = cur->next) { + fprintf(fp, "expression: "); + display_expr(p, cur->expr, fp); + fprintf(fp, "current state: %d\n", cur->cur_state); + fprintf(fp, "True list:\n"); + for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) { + fprintf(fp, "\t"); + render_av_rule(&av_cur->node->key, &av_cur->node->datum, + RENDER_CONDITIONAL, p, fp); + } + fprintf(fp, "False list:\n"); + for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) { + fprintf(fp, "\t"); + render_av_rule(&av_cur->node->key, &av_cur->node->datum, + RENDER_CONDITIONAL, p, fp); + } + } + return 0; +} + +int display_handle_unknown(policydb_t * p, FILE * out_fp) +{ + if (p->handle_unknown == ALLOW_UNKNOWN) + fprintf(out_fp, "Allow unknown classes and permisions\n"); + else if (p->handle_unknown == DENY_UNKNOWN) + fprintf(out_fp, "Deny unknown classes and permisions\n"); + else if (p->handle_unknown == REJECT_UNKNOWN) + fprintf(out_fp, "Reject unknown classes and permisions\n"); + return 0; +} + +int change_bool(char *name, int state, policydb_t * p, FILE * fp) +{ + cond_bool_datum_t *bool; + + bool = hashtab_search(p->p_bools.table, name); + if (bool == NULL) { + fprintf(fp, "Could not find bool %s\n", name); + return -1; + } + bool->state = state; + evaluate_conds(p); + return 0; +} + +static void display_policycaps(policydb_t * p, FILE * fp) +{ + ebitmap_node_t *node; + const char *capname; + char buf[64]; + unsigned int i; + + fprintf(fp, "policy capabilities:\n"); + ebitmap_for_each_bit(&p->policycaps, node, i) { + if (ebitmap_node_get_bit(node, i)) { + capname = sepol_polcap_getname(i); + if (capname == NULL) { + snprintf(buf, sizeof(buf), "unknown (%d)", i); + capname = buf; + } + fprintf(fp, "\t%s\n", capname); + } + } +} + +static void display_id(policydb_t *p, FILE *fp, uint32_t symbol_type, + uint32_t symbol_value, const char *prefix) +{ + const char *id = p->sym_val_to_name[symbol_type][symbol_value]; + fprintf(fp, " %s%s", prefix, id); +} + +static void display_permissive(policydb_t *p, FILE *fp) +{ + ebitmap_node_t *node; + unsigned int i; + + fprintf(fp, "permissive sids:\n"); + ebitmap_for_each_bit(&p->permissive_map, node, i) { + if (ebitmap_node_get_bit(node, i)) { + fprintf(fp, "\t"); + display_id(p, fp, SYM_TYPES, i - 1, ""); + fprintf(fp, "\n"); + } + } +} + +static void display_role_trans(policydb_t *p, FILE *fp) +{ + role_trans_t *rt; + + fprintf(fp, "role_trans rules:\n"); + for (rt = p->role_tr; rt; rt = rt->next) { + display_id(p, fp, SYM_ROLES, rt->role - 1, ""); + display_id(p, fp, SYM_TYPES, rt->type - 1, ""); + display_id(p, fp, SYM_CLASSES, rt->tclass - 1, ":"); + display_id(p, fp, SYM_ROLES, rt->new_role - 1, ""); + fprintf(fp, "\n"); + } +} + +static void display_filename_trans(policydb_t *p, FILE *fp) +{ + filename_trans_t *ft; + + fprintf(fp, "filename_trans rules:\n"); + for (ft = p->filename_trans; ft; ft = ft->next) { + display_id(p, fp, SYM_TYPES, ft->stype - 1, ""); + display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); + display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); + display_id(p, fp, SYM_TYPES, ft->otype - 1, ""); + fprintf(fp, " %s\n", ft->name); + } +} + +int menu(void) +{ + printf("\nSelect a command:\n"); + printf("1) display unconditional AVTAB\n"); + printf("2) display conditional AVTAB (entirely)\n"); + printf("3) display conditional AVTAG (only ENABLED rules)\n"); + printf("4) display conditional AVTAB (only DISABLED rules)\n"); + printf("5) display conditional bools\n"); + printf("6) display conditional expressions\n"); + printf("7) change a boolean value\n"); + printf("8) display role transitions\n"); + printf("\n"); + printf("c) display policy capabilities\n"); + printf("p) display the list of permissive types\n"); + printf("u) display unknown handling setting\n"); + printf("F) display filename_trans rules\n"); + printf("\n"); + printf("f) set output file\n"); + printf("m) display menu\n"); + printf("q) quit\n"); + return 0; +} + +int main(int argc, char **argv) +{ + FILE *out_fp = stdout; + char ans[81], OutfileName[121]; + int fd, ret; + struct stat sb; + void *map; + char *name; + int state; + struct policy_file pf; + + if (argc != 2) + usage(argv[0]); + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open '%s': %s\n", + argv[1], strerror(errno)); + exit(1); + } + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Can't stat '%s': %s\n", + argv[1], strerror(errno)); + exit(1); + } + map = + mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, "Can't map '%s': %s\n", + argv[1], strerror(errno)); + exit(1); + } + + /* read the binary policy */ + fprintf(out_fp, "Reading policy...\n"); + policy_file_init(&pf); + pf.type = PF_USE_MEMORY; + pf.data = map; + pf.len = sb.st_size; + if (policydb_init(&policydb)) { + fprintf(stderr, "%s: Out of memory!\n", argv[0]); + exit(1); + } + ret = policydb_read(&policydb, &pf, 1); + if (ret) { + fprintf(stderr, + "%s: error(s) encountered while parsing configuration\n", + argv[0]); + exit(1); + } + + fprintf(stdout, "binary policy file loaded\n\n"); + close(fd); + + menu(); + for (;;) { + printf("\nCommand (\'m\' for menu): "); + if (fgets(ans, sizeof(ans), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + continue; + } + switch (ans[0]) { + + case '1': + display_avtab(&policydb.te_avtab, RENDER_UNCONDITIONAL, + &policydb, out_fp); + break; + case '2': + display_avtab(&policydb.te_cond_avtab, + RENDER_CONDITIONAL, &policydb, out_fp); + break; + case '3': + display_avtab(&policydb.te_cond_avtab, RENDER_ENABLED, + &policydb, out_fp); + break; + case '4': + display_avtab(&policydb.te_cond_avtab, RENDER_DISABLED, + &policydb, out_fp); + break; + case '5': + display_bools(&policydb, out_fp); + break; + case '6': + display_cond_expressions(&policydb, out_fp); + break; + case '7': + printf("name? "); + if (fgets(ans, sizeof(ans), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + break; + } + ans[strlen(ans) - 1] = 0; + + name = malloc((strlen(ans) + 1) * sizeof(char)); + if (name == NULL) { + fprintf(stderr, "couldn't malloc string.\n"); + break; + } + strcpy(name, ans); + + printf("state? "); + if (fgets(ans, sizeof(ans), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + break; + } + ans[strlen(ans) - 1] = 0; + + if (atoi(ans)) + state = 1; + else + state = 0; + + change_bool(name, state, &policydb, out_fp); + free(name); + break; + case '8': + display_role_trans(&policydb, out_fp); + break; + case 'c': + display_policycaps(&policydb, out_fp); + break; + case 'p': + display_permissive(&policydb, out_fp); + break; + case 'u': + case 'U': + display_handle_unknown(&policydb, out_fp); + break; + case 'f': + printf + ("\nFilename for output (<CR> for screen output): "); + if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) { + fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, + strerror(errno)); + break; + } + OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ + if (strlen(OutfileName) == 0) + out_fp = stdout; + else if ((out_fp = fopen(OutfileName, "w")) == NULL) { + fprintf(stderr, "Cannot open output file %s\n", + OutfileName); + out_fp = stdout; + } + if (out_fp != stdout) + printf("\nOutput to file: %s\n", OutfileName); + break; + case 'F': + display_filename_trans(&policydb, out_fp); + break; + case 'q': + policydb_destroy(&policydb); + exit(0); + break; + case 'm': + menu(); + break; + default: + printf("\nInvalid choice\n"); + menu(); + break; + + } + } +} + +/* FLASK */
diff --git a/selinux/libselinux/ChangeLog b/selinux/libselinux/ChangeLog new file mode 100644 index 0000000..afb5735 --- /dev/null +++ b/selinux/libselinux/ChangeLog
@@ -0,0 +1,1246 @@ + * Respect CC and PKG_CONFIG environment variable, from Julien Pivotto. + * Avoid mounting /proc outside of selinux_init_load_policy(), from Stephen Smalley. + * Fix multiple spelling errors, from Laurent Bigonville. + * Fix typo in sefcontext_compile.8, from Petr Lautrbach and Milos Malik + * Fix location of selinuxfs mount point, from Dan Walsh. + * Only mount /proc if necessary, from Stephen Smalley. + * procattr: return einval for <= 0 pid args, from Daniel Cashman. + * procattr: return error on invalid pid_t input, from Daniel Cashman. + +2.5 2016-02-23 + * selinux_restorecon.3 man page corrections, from Richard Haines. + * Add selinux_restorecon function, from Richard Haines. + * read_spec_entry: fail on non-ascii, from William Roberts. + * Add man information about thread specific functions, from Dan Waslh. + * Don't wrap rpm_execcon with DISABLE_RPM with SWIG, from Petr Lautrbach. + * Correct line count for property and service context files, from Richard Haines. + * Man page warning fixes, from Ville Skyttä. + * label_file: fix memory leaks and uninitialized jump, from William Roberts. + * Replace selabel_digest hash function, from Richard Haines. + * Fix selabel_open(3) services if no digest requested, from Richard Haines. + * Add selabel_digest function, from Richard Haines. + * Fix parallel build with swig python, from Jason Zaman. + * Flush the class/perm string mapping cache on policy reload, from Stephen Smalley. + * Fix restorecon when path has no context, from Nir Soffer. + * Free memory when processing media and x specfiles, from Richard Haines. + * Fix mmap memory release for file labeling, from Richard Haines. + * Add explicit dependency for pywrap on selinux.py, from Wenzong Fan. + * Add policy context validation to sefcontext_compile, from Richard Haines. + * Do not treat an empty file_contexts(.local) as an error, from Stephen Smalley. + * Fail hard on invalid property_contexts entries, from Stephen Smalley. + * Fail hard on invalid file_contexts entries, from Stephen Smalley. + * Support context validation on file_contexts.bin, from Stephen Smalley. + * Test for file_contexts.bin format by magic number, from Stephen Smalley. + * Add selabel_cmp interface and label_file backend, from Stephen Smalley. + * Support specifying file_contexts.bin file path, from Stephen Smalley. + * Support file_contexts.bin without file_contexts, from Stephen Smalley. + * Simplify procattr cache, from Stephen Smalley. + * Use /proc/thread-self when available, from Stephen Smalley. + * Add const to selinux_opt for label backends, from Richard Haines. + * Fix binary file labels for regexes with metachars, from Richard Haines. + * Fix file labels for regexes with metachars, from Jeff Vander Stoep. + * Fix if file_contexts not '\n' terminated, from Richard Haines. + * Enhance file context support, from Richard Haines. + * Fix property processing and cleanup formatting, from Richard Haines. + * Add read_spec_entries function to replace sscanf, from Richard Haines. + * Support consistent mode size for bin files, from Richard Haines. + * Expunge remaining references to flask.h and av_permissions.h, from Stephen Smalley. + * Fix more bin file processing core dumps, from Richard Haines. + * add selinux_openssh_contexts_path(), from Petr Lautrbach. + * setrans_client: minimize overhead when mcstransd is not present, from Stephen Smalley. + * Ensure selabel_lookup_best_match links NULL terminated, from Richard Haines. + * is_selinux_enabled: Add /etc/selinux/config test, from Stephen Smalley. + * matchpathcon/selabel_file: Fix man pages, from Stephen Smalley. + * Fix core dumps with corrupt *.bin files, from Richard Haines. + * Add selabel partial and best match APIs, from Richard Haines. + * Use os.walk() instead of the deprecated os.path.walk(), from Petr + Lautrbach & Miro Hrončok + * is_selinux_enabled(): drop no-policy-loaded test, from Stephen Smalley. + * Remove deprecated mudflap option, from Stephen Smalley. + * Mount procfs before checking /proc/filesystems, from Ben Shelton. + * Fix -Wformat errors with gcc-5.0.0, from Petr Lautrbach. + * label_file: handle newlines in file names, from Nick Kralevich. + * getcon.3: Fix setcon description, from Stephen Smalley. + * Fix audit2why error handling if SELinux is disabled, from Stephen Smalley. + * pcre_study can return NULL without error, from Stephen Smalley. + * Android property backend validation support, from Robert Craig. + * Only check SELinux enabled status once in selinux_check_access, from Stephen Smalley. + +2.4 2015-02-02 + * Remove assumption that SHLIBDIR is ../../ relative to LIBDIR, from Steve + Lawrence + * Fix bugs found by hardened gcc flags, from Nicolas Iooss. + * Set the system to permissive if failing to disable SELinux because + policy has already been loaded, from Will Woods. + * Fix type in selinux.8 manpage, from Nicolas Iooss + * Add db_exception and db_datatype support to label_db backend, from Artyom + Smirnov + * Log an error on unknown classes and permissions, from Stephen Smalley + * Add pcre version string to the compiled file_contexts format, from + Stephen Smalley + * Deprecate use of flask.h and av_permissions.h, from Stephen Smalley + * Compiled file_context files and the original should have the same DAC + permissions, from Dan Walsh + +2.3 2014-05-06 + * Get rid of security_context_t and fix const declarations. + * Refactor rpm_execcon() into a new setexecfilecon() from Guillem Jover. + +2.2.2 2013-12-30 + * Fix userspace AVC handling of per-domain permissive mode. + +2.2.1 2013-11-06 + * Remove -lpthread from pkg-config file; it is not required. + +2.2 2013-10-30 + * Fix avc_has_perm() returns -1 even when SELinux is in permissive mode. + * Support overriding Makefile RANLIB from Sven Vermeulen. + * Update pkgconfig definition from Sven Vermeulen. + * Mount sysfs before trying to mount selinuxfs from Sven Vermeulen. + * Fix man pages from Laurent Bigonville. + * Support overriding PATH and LIBBASE in Makefiles from Laurent Bigonville. + * Fix LDFLAGS usage from Laurent Bigonville + * Avoid shadowing stat in load_mmap from Joe MacDonald. + * Support building on older PCRE libraries from Joe MacDonald. + * Fix handling of temporary file in sefcontext_compile from Dan Walsh. + * Fix procattr cache from Dan Walsh. + * Define python constants for getenforce result from Dan Walsh. + * Fix label substitution handling of / from Dan Walsh. + * Add selinux_current_policy_path from Dan Walsh. + * Change get_context_list to only return good matches from Dan Walsh. + * Support udev-197 and higher from Sven Vermeulen and Dan Walsh. + * Add support for local substitutions from Dan Walsh. + * Change setfilecon to not return ENOSUP if context is already correct from Dan Walsh. + * Python wrapper leak fixes from Dan Walsh. + * Export SELINUX_TRANS_DIR definition in selinux.h from Dan Walsh. + * Add selinux_systemd_contexts_path from Dan Walsh. + * Add selinux_set_policy_root from Dan Walsh. + * Add man page for sefcontext_compile from Dan Walsh. + +2.1.13 2013-02-01 + * audit2why: make sure path is nul terminated + * utils: new file context regex compiler + * label_file: use precompiled filecontext when possible + * do not leak mmapfd + * sefcontontext_compile: Add error handling to help debug problems in libsemanage. + * man: make selinux.8 mention service man pages + * audit2why: Fix segfault if finish() called twice + * audit2why: do not leak on multiple init() calls + * mode_to_security_class: interface to translate a mode_t in to a security class + * audit2why: Cleanup audit2why analysys function + * man: Fix program synopsis and function prototypes in man pages + * man: Fix man pages formatting + * man: Fix typo in man page + * man: Add references and man page links to _raw function variants + * Use ENOTSUP instead of EOPNOTSUPP for getfilecon functions + * man: context_new(3): fix the return value description + * selinux_status_open: handle error from sysconf + * selinux_status_open: do not leak statusfd on exec + * Fix errors found by coverity + * Change boooleans.subs to booleans.subs_dist. + * optimize set*con functions + * pkg-config do not specifc ruby version + * unmap file contexts on selabel_close() + * do not leak file contexts with mmap'd backend + * sefcontext_compile: do not leak fd on error + * matchmediacon: do not leak fd + * src/label_android_property: do not leak fd on error + +2.1.12 2012-09-13 + * Add support for lxc_contexts_path + * utils: add service to getdefaultcon + * libsemanage: do not set soname needlessly + * libsemanage: remove PYTHONLIBDIR and ruby equivalent + * boolean name equivalency + * getsebool: support boolean name substitution + * Add man page for new selinux_boolean_sub function. + * expose selinux_boolean_sub + * matchpathcon: add -m option to force file type check + * utils: avcstat: clear sa_mask set + * seusers: Check for strchr failure + * booleans: initialize pointer to silence coveriety + * stop messages when SELinux disabled + * label_file: use PCRE instead of glibc regex functions + * label_file: remove all typedefs + * label_file: move definitions to include file + * label_file: do string to mode_t conversion in a helper function + * label_file: move error reporting back into caller + * label_file: move stem/spec handling to header + * label_file: drop useless ncomp field from label_file data + * label_file: move spec_hasMetaChars to header + * label_file: fix potential read past buffer in spec_hasMetaChars + * label_file: move regex sorting to the header + * label_file: add accessors for the pcre extra data + * label_file: only run regex files one time + * label_file: new process_file function + * label_file: break up find_stem_from_spec + * label_file: struct reorg + * label_file: only run array once when sorting + * Ensure that we only close the selinux netlink socket once. + * improve the file_contexts.5 manual page + +2.1.11 2012-06-28 + * Fortify source now requires all code to be compiled with -O flag + * asprintf return code must be checked + * avc_netlink_recieve handle EINTR + * audit2why: silence -Wmissing-prototypes warning + * libsemanage: remove build warning when build swig c files + * matchpathcon: bad handling of symlinks in / + * seusers: remove unused lineno + * seusers: getseuser: gracefully handle NULL service + * New Android property labeling backend + * label_android_property whitespace cleanups + * additional makefile support for rubywrap + + +2.1.10 2012-03-28 + * Fix dead links to www.nsa.gov/selinux + * Remove jump over variable declaration + * Fix old style function definitions + * Fix const-correctness + * Remove unused flush_class_cache method + * Add prototype decl for destructor + * Add more printf format annotations + * Add printf format attribute annotation to die() method + * Fix const-ness of parameters & make usage() methods static + * Enable many more gcc warnings for libselinux/src/ builds + * utils: Enable many more gcc warnings for libselinux/utils builds + * Change annotation on include/selinux/avc.h to avoid upsetting SWIG + * Ensure there is a prototype for 'matchpathcon_lib_destructor' + * Update Makefiles to handle /usrmove + * utils: Stop separating out matchpathcon as something special + * pkg-config to figure out where ruby include files are located + * build with either ruby 1.9 or ruby 1.8 + * assert if avc_init() not called + * take security_deny_unknown into account + * security_compute_create_name(3) + * Do not link against python library, this is considered + * bad practice in debian + * Hide unnecessarily-exported library destructors + +2.1.9 2011-12-21 + * Fix setenforce man page to refer to selinux man page + * Cleanup Man pages + * merge freecon with getcon man page + +2.1.8 2011-12-05 + * selinuxswig_python.i: don't make syscall if it won't change anything + * Remove assert in security_get_boolean_names(3) + * Mapped compute functions now obey deny_unknown flag + * get_default_type now sets EINVAL if no entry. + * return EINVAL if invalid role selected + * Updated selabel_file(5) man page + * Updated selabel_db(5) man page + * Updated selabel_media(5) man page + * Updated selabel_x(5) man page + * Add man/man5 man pages + * Add man/man5 man pages + * Add man/man5 man pages + * use -W and -Werror in utils + +2.1.7 2011-11-03 + * Makefiles: syntax, convert all ${VAR} to $(VAR) + * load_policy: handle selinux=0 and /sys/fs/selinux not exist + * regenerate .pc on VERSION change + * label: cosmetic cleanups + * simple interface for access checks + * Don't reinitialize avc_init if it has been called previously + * seusers: fix to handle large sets of groups + * audit2why: close fd on enomem + * rename and export symlink_realpath + * label_file: style changes to make Eric happy. + +2.1.6 2011-09-15 + * utils: matchpathcon: remove duplicate declaration + * src: matchpathcon: use myprintf not fprintf + * src: matchpathcon: make sure resolved path starts + * put libselinux.so.1 in /lib not /usr/lib + * tree: default make target to all not + +2.1.5 2011-0826 + * selinux_file_context_verify function returns wrong value. + * move realpath helper to matchpathcon library + * python wrapper makefile changes + +2.1.4 2011-0817 + * mapping fix for invalid class/perms after selinux_set_mapping + * audit2why: work around python bug not defining + * resolv symlinks and dot directories before matching + +2.1.2 2011-0803 + * audit2allow: do not print statistics + * make python bindings for restorecon work on relative path + * fix python audit2why binding error + * support new python3 functions + * do not check fcontext duplicates on use + * Patch for python3 for libselinux + +2.1.1 2011-08-02 + * move .gitignore into utils + * new setexecon utility + * selabel_open fix processing of substitution files + * mountpoint changing patch. + * simplify SRCS in Makefile + +2.1.1 2011-08-01 + * Remove generated files, introduce more .gitignore + +2.1.0 2011-07-27 + * Release, minor version bump + +2.0.102 2011-04-11 + * Give correct names to mount points in load_policy by Dan Walsh. + * Make sure selinux state is reported correctly if selinux is disabled or + fails to load by Dan Walsh. + * Fix crash if selinux_key_create was never called by Dan Walsh. + * Add new file_context.subs_dist for distro specific filecon substitutions + by Dan Walsh. + * Update man pages for selinux_color_* functions by Richard Haines. + +2.0.101 2011-03-23 + * db_language object class support for selabel_lookup from KaiGai + Kohei. + +2.0.100 2011-03-09 + * Library destructors for thread local storage keys from Eamon Walsh. + +2.0.99 2011-03-01 + * SELinux man page fixes from Dan Walsh. + * selinux_status interfaces from KaiGai Kohei. + +2.0.98 2010-12-16 + * Turn off default user handling when computing user contexts by Dan Walsh + +2.0.97 2010-12-02 + * Thread local storage fixes from Eamon Walsh. + +2.0.96 2010-06-14 + * Add const qualifiers to public API where appropriate by KaiGai Kohei. + +2.0.95 2010-06-10 + * Remove duplicate slashes in paths in selabel_lookup from Chad Sellers + * Adds a chcon method to the libselinux python bindings from Steve Lawrence + +2.0.94 2010-03-24 + * Set errno=EINVAL for invalid contexts from Dan Walsh. + +2.0.93 2010-03-15 + * Show strerror for security_getenforce() by Colin Walters. + * Merged selabel database support by KaiGai Kohei. + * Modify netlink socket blocking code by KaiGai Kohei. + +2.0.92 2010-03-06 + * Fix from Eric Paris to fix leak on non-selinux systems. + * regenerate swig wrappers + * pkgconfig fix to respect LIBDIR from Dan Walsh. + +2.0.91 2010-02-22 + * Change the AVC to only audit the permissions specified by the + policy, excluding any permissions specified via dontaudit or not + specified via auditallow. + * Fix compilation of label_file.c with latest glibc headers. + +2.0.90 2009-11-27 + * add/reformat man pages by Guido Trentalancia <guido@trentalancia.com>. + * Change exception.sh to be called with bash by Manoj Srivastava <srivasta@debian.org> + +2.0.89 2009-10-29 + * Add pkgconfig file from Eamon Walsh. + +2.0.88 2009-10-22 + * Rename and export selinux_reset_config() + +2.0.87 2009-09-25 + * Add exception handling in libselinux from Dan Walsh. This uses a + shell script called exception.sh to generate a swig interface file. + * make swigify + * Make matchpathcon print <<none>> if path not found in fcontext file. + +2.0.86 2009-09-02 + * Removal of reference counting on userspace AVC SID's. + +2.0.85 2009-07-14 + * Reverted Tomas Mraz's fix for freeing thread local storage to avoid + pthread dependency. + * Removed fini_context_translations() altogether. + * Merged lazy init patch from Stephen Smalley based on original patch + by Steve Grubb. + +2.0.84 2009-07-07 + * Add per-service seuser support from Dan Walsh. + * Let load_policy gracefully handle selinuxfs being mounted from Stephen Smalley. + +2.0.83 2009-07-07 + * Check /proc/filesystems before /proc/mounts for selinuxfs from Eric + Paris. + +2.0.82 2009-06-19 + * Fix improper use of thread local storage from Tomas Mraz <tmraz@redhat.com>. + * Label substitution support from Dan Walsh. + * Support for labeling virtual machine images from Dan Walsh. + +2.0.81 2009-05-15 + * Trim / from the end of input paths to matchpathcon from Dan Walsh. + * Fix leak in process_line in label_file.c from Hiroshi Shinji. + * Move matchpathcon to /sbin, add matchpathcon to clean target from Dan Walsh. + * getdefaultcon to print just the correct match and add verbose option from Dan Walsh. + +2.0.80 2009-04-07 + * deny_unknown wrapper function from KaiGai Kohei. + * security_compute_av_flags API from KaiGai Kohei. + * Netlink socket management and callbacks from KaiGai Kohei. + +2.0.79 2009-03-11 + * Netlink socket handoff patch from Adam Jackson. + * AVC caching of compute_create results by Eric Paris. + +2.0.78 2009-02-27 + * Fix incorrect conversion in discover_class code. + +2.0.77 2009-01-12 + * add restorecon to python bindings from Dan Walsh. + +2.0.76 2009-01-08 + * Client support for translating raw contexts to colors via setrans. + +2.0.75 2008-11-18 + * Allow shell-style wildcards in x_contexts file. + +2.0.74 2008-11-03 + * Correct message types in AVC log messages. + +2.0.73 2008-10-14 + * Make matchpathcon -V pass mode from Dan Walsh. + * Add man page for selinux_file_context_cmp from Dan Walsh. + +2.0.72 2008-09-29 + * New man pages from Dan Walsh. + * Update flask headers from refpolicy trunk from Dan Walsh. + +2.0.71 2008-08-05 + * Add group support to seusers using %groupname syntax from Dan Walsh. + * Mark setrans socket close-on-exec from Stephen Smalley. + * Only apply nodups checking to base file contexts from Stephen Smalley. + +2.0.70 2008-07-30 + * Merge ruby bindings from Dan Walsh. + +2.0.69 2008-07-29 + * Handle duplicate file context regexes as a fatal error from Stephen Smalley. + This prevents adding them via semanage. + +2.0.68 2008-07-18 + * Fix audit2why shadowed variables from Stephen Smalley. + * Note that freecon NULL is legal in man page from Karel Zak. + +2.0.67 2008-06-13 + * New and revised AVC, label, and mapping man pages from Eamon Walsh. + +2.0.66 2008-06-11 + * Add swig python bindings for avc interfaces from Dan Walsh. + +2.0.65 2008-05-27 + * Fix selinux_file_context_verify() and selinux_lsetfilecon_default() to call matchpathcon_init_prefix if not already initialized. + * Add -q qualifier for -V option of matchpathcon and change it to indicate whether verification succeeded or failed via exit status. + +2.0.64 2008-04-21 + * Fixed selinux_set_callback man page. + +2.0.63 2008-04-18 + * Try loading the max of the kernel-supported version and the libsepol-supported version when no manipulation of the binary policy is needed from Stephen Smalley. + +2.0.62 2008-04-18 + * Fix memory leaks in matchpathcon from Eamon Walsh. + +2.0.61 2008-03-31 + * Man page typo fix from Jim Meyering. + +2.0.60 2008-03-20 + * Changed selinux_init_load_policy() to not warn about a failed mount of selinuxfs if selinux was disabled in the kernel. + +2.0.59 2008-02-29 + * Merged new X label "poly_selection" namespace from Eamon Walsh. + +2.0.58 2008-02-28 + * Merged reset_selinux_config() for load policy from Dan Walsh. + +2.0.57 2008-02-25 + * Merged avc_has_perm() errno fix from Eamon Walsh. + +2.0.56 2008-02-21 + * Regenerated Flask headers from refpolicy flask definitions. + +2.0.55 2008-02-08 + * Merged compute_member AVC function and manpages from Eamon Walsh. + +2.0.54 2008-02-08 + * Provide more error reporting on load policy failures from Stephen Smalley. + +2.0.53 2008-02-07 + * Merged new X label "poly_prop" namespace from Eamon Walsh. + +2.0.52 2008-02-06 + * Disable setlocaldefs if no local boolean or users files are present from Stephen Smalley. + +2.0.51 2008-02-05 + * Skip userspace preservebools processing for Linux >= 2.6.22 from Stephen Smalley. + +2.0.50 2008-01-28 + * Merged fix for audit2why from Dan Walsh. + +2.0.49 2008-01-23 + * Merged audit2why python binding from Dan Walsh. + +2.0.48 2008-01-23 + * Merged updated swig bindings from Dan Walsh, including typemap for pid_t. + +2.0.47 2007-12-21 + * Fix for the avc: granted null message bug from Stephen Smalley. + +2.0.46 2007-12-07 + * matchpathcon(8) man page update from Dan Walsh. + +2.0.45 2007-11-20 + * dlopen libsepol.so.1 rather than libsepol.so from Stephen Smalley. + +2.0.44 2007-11-20 + * Based on a suggestion from Ulrich Drepper, defer regex compilation until we have a stem match, by Stephen Smalley. + A further optimization would be to defer regex compilation until we have a complete match of the constant prefix of the regex - TBD. + +2.0.43 2007-11-15 + * Regenerated Flask headers from policy. + +2.0.42 2007-11-08 + * AVC enforcing mode override patch from Eamon Walsh. + +2.0.41 2007-11-06 + * Aligned attributes in AVC netlink code from Eamon Walsh. + +2.0.40 2007-11-01 + * Merged refactored AVC netlink code from Eamon Walsh. + +2.0.39 2007-10-19 + * Merged new X label namespaces from Eamon Walsh. + +2.0.38 2007-10-15 + * Bux fix and minor refactoring in string representation code. + +2.0.37 2007-10-05 + * Merged selinux_get_callback, avc_open, empty string mapping from Eamon Walsh. + +2.0.36 2007-09-27 + * Fix segfault resulting from missing file_contexts file. + +2.0.35 2007-09-24 + * Make netlink socket close-on-exec to avoid descriptor leakage from Dan Walsh. + * Pass CFLAGS when using gcc for linking from Dennis Gilmore. + +2.0.34 2007-09-18 + * Fix selabel option flag setting for 64-bit from Stephen Smalley. + +2.0.33 2007-09-12 + * Re-map a getxattr return value of 0 to a getfilecon return value of -1 with errno EOPNOTSUPP from Stephen Smalley. + * Fall back to the compat code for security_class_to_string and security_av_perm_to_string from Stephen Smalley. + +2.0.32 2007-09-10 + * Fix swig binding for rpm_execcon from James Athey. + +2.0.31 2007-08-23 + * Fix file_contexts.homedirs path from Todd Miller. + +2.0.30 2007-08-06 + * Fix segfault resulting from uninitialized print-callback pointer. + +2.0.29 2007-08-02 + * Added x_contexts path function patch from Eamon Walsh. + +2.0.28 2007-08-01 + * Fix build for EMBEDDED=y from Yuichi Nakamura. + +2.0.27 2007-07-25 + * Fix markup problems in selinux man pages from Dan Walsh. + +2.0.26 2007-07-23 + * Updated av_permissions.h and flask.h to include new nscd permissions from Dan Walsh. + * Added swigify to top-level Makefile from Dan Walsh. + +2.0.25 2007-07-23 + * Fix for string_to_security_class segfault on x86_64 from Stephen + Smalley. + +2.0.24 2007-09-07 + * Fix for getfilecon() for zero-length contexts from Stephen Smalley. + +2.0.23 2007-06-22 + * Refactored SWIG bindings from James Athey. + +2.0.22 2007-06-20 + * Labeling and callback interface patches from Eamon Walsh. + +2.0.21 2007-06-11 + * Class and permission mapping support patches from Eamon Walsh. + +2.0.20 2007-06-07 + * Object class discovery support patches from Chris PeBenito. + +2.0.19 2007-06-05 + * Refactoring and errno support in string representation code. + +2.0.18 2007-05-31 + * Merged patch to reduce size of libselinux and remove need for libsepol for embedded systems from Yuichi Nakamura. + This patch also turns the link-time dependency on libsepol into a runtime (dlopen) dependency even in the non-embedded case. + +2.0.17 2007-05-31 + * Updated Lindent script and reindented two header files. + +2.0.16 2007-05-09 + * Merged additional swig python bindings from Dan Walsh. + +2.0.15 2007-04-27 + * Merged helpful message when selinuxfs mount fails patch from Dax Kelson. + +2.0.14 2007-04-24 + * Merged build fix for avc_internal.c from Joshua Brindle. + +2.0.13 2007-04-12 + * Merged rpm_execcon python binding fix, matchpathcon man page fix, and getsebool -a handling for EACCES from Dan Walsh. + +2.0.12 2007-04-09 + * Merged support for getting initial contexts from James Carter. + +2.0.11 2007-04-05 + * Merged userspace AVC patch to follow kernel's behavior for permissive mode in caching previous denials from Eamon Walsh. + + +2.0.10 2007-04-05 + * Merged sidput(NULL) patch from Eamon Walsh. + +2.0.9 2007-03-30 + * Merged class/av string conversion and avc_compute_create patch from Eamon Walsh. + +2.0.8 2007-03-20 + * Merged fix for avc.h #include's from Eamon Walsh. + +2.0.7 2007-03-12 + * Merged patch to drop support for CACHETRANS=0 config option from Steve Grubb. + +2.0.6 2007-03-12 + * Merged patch to drop support for old /etc/sysconfig/selinux and + /etc/security policy file layout from Steve Grubb. + +2.0.5 2007-02-27 + * Merged init_selinuxmnt() and is_selinux_enabled() improvements from Steve Grubb. + +2.0.4 2007-02-23 + * Removed sending of setrans init message. + +2.0.3 2007-02-22 + * Merged matchpathcon memory leak fix from Steve Grubb. + +2.0.2 2007-02-21 + * Merged more swig initializers from Dan Walsh. + +2.0.1 2007-02-20 + * Merged patch from Todd Miller to convert int types over to C99 style. + +2.0.0 2007-02-01 + * Merged patch from Todd Miller to remove sscanf in matchpathcon.c because + of the use of the non-standard format %as. (original patch changed + for style). + * Merged patch from Todd Miller to fix memory leak in matchpathcon.c. + +1.34.1 2007-01-26 + * Merged python binding fixes from Dan Walsh. + +1.34.0 2007-01-18 + * Updated version for stable branch. + +1.33.6 2007-01-17 + * Merged man page updates to make "apropos selinux" work from Dan Walsh. + +1.33.5 2007-01-16 + * Merged getdefaultcon utility from Dan Walsh. + +1.33.4 2007-01-11 + * Merged selinux_check_securetty_context() and support from Dan Walsh. + +1.33.3 2007-01-04 + * Merged patch for matchpathcon utility to use file mode information + when available from Dan Walsh. + +1.33.2 2006-11-27 + * Merged patch to compile with -fPIC instead of -fpic from + Manoj Srivastava to prevent hitting the global offset table + limit. Patch changed to include libsepol and libsemanage in + addition to libselinux. + +1.33.1 2006-10-19 + * Merged updated flask definitions from Darrel Goeddel. + This adds the context security class, and also adds + the string definitions for setsockcreate and polmatch. + +1.32 2006-10-17 + * Updated version for release. + +1.30.30 2006-10-05 + * Merged patch from Darrel Goeddel to always use untranslated + contexts in the userspace AVC. + +1.30.29 2006-09-29 + * Merged av_permissions.h update from Steve Grubb, + adding setsockcreate and polmatch definitions. + +1.30.28 2006-09-13 + * Merged patch from Steve Smalley to fix SIGPIPE in setrans_client + * Merged c++ class identifier fix from Joe Nall. + +1.30.27 2006-08-24 + * Merged patch to not log avc stats upon a reset from Steve Grubb. + * Applied patch to revert compat_net setting upon policy load. + +1.30.26 2006-08-11 + * Merged file context homedir and local path functions from + Chris PeBenito. + +1.30.25 2006-08-11 + * Rework functions that access /proc/pid/attr to access the + per-thread nodes, and unify the code to simplify maintenance. + +1.30.24 2006-08-10 + * Merged return value fix for *getfilecon() from Dan Walsh. + +1.30.23 2006-08-10 + * Merged sockcreate interfaces from Eric Paris. + +1.30.22 2006-08-03 + * Merged no-tls-direct-seg-refs patch from Jeremy Katz. + +1.30.21 2006-08-03 + * Merged netfilter_contexts support patch from Chris PeBenito. + +1.30.20 2006-08-01 + * Merged context_*_set errno patch from Jim Meyering. + +1.30.19 2006-06-29 + * Lindent. + +1.30.18 2006-06-27 + * Merged {get,set}procattrcon patch set from Eric Paris. + * Merged re-base of keycreate patch originally by Michael LeMay from Eric Paris. + +1.30.17 2006-06-27 + * Regenerated Flask headers from refpolicy. + +1.30.16 2006-06-26 + * Merged patch from Dan Walsh with: + - Added selinux_file_context_{cmp,verify}. + - Added selinux_lsetfilecon_default. + - Delay translation of contexts in matchpathcon. + +1.30.15 2006-06-16 + * Merged patch from Dan Walsh with: + * Added selinux_getpolicytype() function. + * Modified setrans code to skip processing if !mls_enabled. + +1.30.14 2006-06-16 + * Set errno in the !selinux_mnt case. + +1.30.13 2006-06-02 + * Allocate large buffers from the heap, not on stack. + Affects is_context_customizable, selinux_init_load_policy, + and selinux_getenforcemode. + +1.30.12 2006-06-02 + * Merged !selinux_mnt checks from Ian Kent. + +1.30.11 2006-05-24 + * Merged matchmediacon and trans_to_raw_context fixes from + Serge Hallyn. + +1.30.10 2006-05-22 + * Merged simple setrans client cache from Dan Walsh. + Merged avcstat patch from Russell Coker. + +1.30.9 2006-05-22 + * Modified selinux_mkload_policy() to also set /selinux/compat_net + appropriately for the loaded policy. + +1.30.8 2006-05-17 + * Added matchpathcon_fini() function to free memory allocated by + matchpathcon_init(). + +1.30.7 2006-05-16 + * Merged setrans client cleanup patch from Steve Grubb. + +1.30.6 2006-05-08 + * Merged getfscreatecon man page fix from Dan Walsh. + * Updated booleans(8) man page to drop references to the old + booleans file and to note that setsebool can be used to set + the boot-time defaults via -P. + +1.30.5 2006-05-05 + * Merged fix warnings patch from Karl MacMillan. + +1.30.4 2006-05-05 + * Merged setrans client support from Dan Walsh. + This removes use of libsetrans. + * Merged patch to eliminate use of PAGE_SIZE constant from Dan Walsh. + * Merged swig typemap fixes from Glauber de Oliveira Costa. + +1.30.3 2006-04-12 + * Added distclean target to Makefile. + * Regenerated swig files. + +1.30.2 2006-04-11 + * Changed matchpathcon_init to verify that the spec file is + a regular file. + * Merged python binding t_output_helper removal patch from Dan Walsh. + +1.30.1 2006-03-20 + * Merged Makefile PYLIBVER definition patch from Dan Walsh. + +1.30 2006-03-14 + * Updated version for release. + +1.29.8 2006-02-27 + * Altered rpm_execcon fallback logic for permissive mode to also + handle case where /selinux/enforce is not available. + +1.29.7 2006-01-20 + * Merged install-pywrap Makefile patch from Joshua Brindle. + +1.29.6 2006-01-18 + * Merged pywrap Makefile patch from Dan Walsh. + +1.29.5 2006-01-11 + * Added getseuser test program. + +1.29.4 2006-01-06 + * Added format attribute to myprintf in matchpathcon.c and + removed obsoleted rootlen variable in init_selinux_config(). + +1.29.3 2006-01-04 + * Merged several fixes and improvements from Ulrich Drepper + (Red Hat), including: + - corrected use of getline + - further calls to __fsetlocking for local files + - use of strdupa and asprintf + - proper handling of dirent in booleans code + - use of -z relro + - several other optimizations + * Merged getpidcon python wrapper from Dan Walsh (Red Hat). + +1.29.2 2005-12-14 + * Merged call to finish_context_translations from Dan Walsh. + This eliminates a memory leak from failing to release memory + allocated by libsetrans. + +1.29.1 2005-12-08 + * Merged patch for swig interfaces from Dan Walsh. + +1.28 2005-12-07 + * Updated version for release. + +1.27.28 2005-12-01 + * Added MATCHPATHCON_VALIDATE flag for set_matchpathcon_flags() and + modified matchpathcon implementation to make context validation/ + canonicalization optional at matchpathcon_init time, deferring it + to a successful matchpathcon by default unless the new flag is set + by the caller. + +1.27.27 2005-12-01 + * Added matchpathcon_init_prefix() interface, and + reworked matchpathcon implementation to support selective + loading of file contexts entries based on prefix matching + between the pathname regex stems and the specified path + prefix (stem must be a prefix of the specified path prefix). + +1.27.26 2005-11-29 + * Merged getsebool patch from Dan Walsh. + +1.27.25 2005-11-29 + * Added -f file_contexts option to matchpathcon util. + Fixed warning message in matchpathcon_init(). + +1.27.24 2005-11-29 + * Merged Makefile python definitions patch from Dan Walsh. + +1.27.23 2005-11-28 + * Merged swigify patch from Dan Walsh. + +1.27.22 2005-11-15 + * Merged make failure in rpm_execcon non-fatal in permissive mode + patch from Ivan Gyurdiev. + +1.27.21 2005-11-08 + * Added MATCHPATHCON_NOTRANS flag for set_matchpathcon_flags() + and modified matchpathcon_init() to skip context translation + if it is set by the caller. + +1.27.20 2005-11-07 + * Added security_canonicalize_context() interface and + set_matchpathcon_canoncon() interface for obtaining + canonical contexts. Changed matchpathcon internals + to obtain canonical contexts by default. Provided + fallback for kernels that lack extended selinuxfs context + interface. + +1.27.19 2005-11-04 + * Merged seusers parser changes from Ivan Gyurdiev. + * Merged setsebool to libsemanage patch from Ivan Gyurdiev. + * Changed seusers parser to reject empty fields. + +1.27.18 2005-11-03 + * Merged seusers empty level handling patch from Jonathan Kim (TCS). + +1.27.17 2005-10-27 + * Changed default entry for seusers to use __default__ to avoid + ambiguity with users named "default". + +1.27.16 2005-10-27 + * Fixed init_selinux_config() handling of missing /etc/selinux/config + or missing SELINUXTYPE= definition. + * Merged selinux_translations_path() patch from Dan Walsh. + +1.27.15 2005-10-25 + * Added hidden_proto/def for get_default_context_with_role. + +1.27.14 2005-10-25 + * Merged selinux_path() and selinux_homedir_context_path() + functions from Joshua Brindle. + +1.27.13 2005-10-19 + * Merged fixes for make DESTDIR= builds from Joshua Brindle. + +1.27.12 2005-10-18 + * Merged get_default_context_with_rolelevel and man pages from + Dan Walsh (Red Hat). + +1.27.11 2005-10-18 + * Updated call to sepol_policydb_to_image for sepol changes. + +1.27.10 2005-10-17 + * Changed getseuserbyname to ignore empty lines and to handle + no matching entry in the same manner as no seusers file. + +1.27.9 2005-10-13 + * Changed selinux_mkload_policy to try downgrading the + latest policy version available to the kernel-supported version. + +1.27.8 2005-10-11 + * Changed selinux_mkload_policy to fall back to the maximum + policy version supported by libsepol if the kernel policy version + falls outside of the supported range. + +1.27.7 2005-10-06 + * Changed getseuserbyname to fall back to the Linux username and + NULL level if seusers config file doesn't exist unless + REQUIRESEUSERS=1 is set in /etc/selinux/config. + * Moved seusers.conf under $SELINUXTYPE and renamed to seusers. + +1.27.6 2005-10-06 + * Added selinux_init_load_policy() function as an even higher level + interface for the initial policy load by /sbin/init. This obsoletes + the load_policy() function in the sysvinit-selinux.patch. + +1.27.5 2005-10-06 + * Added selinux_mkload_policy() function as a higher level interface + for loading policy than the security_load_policy() interface. + +1.27.4 2005-10-05 + * Merged fix for matchpathcon (regcomp error checking) from Johan + Fischer. Also added use of regerror to obtain the error string + for inclusion in the error message. + +1.27.3 2005-10-03 + * Changed getseuserbyname to not require (and ignore if present) + the MLS level in seusers.conf if MLS is disabled, setting *level + to NULL in this case. + +1.27.2 2005-09-30 + * Merged getseuserbyname patch from Dan Walsh. + +1.27.1 2005-09-19 + * Merged STRIP_LEVEL patch for matchpathcon from Dan Walsh. + This allows file_contexts with MLS fields to be processed on + non-MLS-enabled systems with policies that are otherwise + identical (e.g. same type definitions). + * Merged get_ordered_context_list_with_level() function from + Dan Walsh, and added get_default_context_with_level(). + This allows MLS level selection for users other than the + default level. + +1.26 2005-09-06 + * Updated version for release. + +1.25.7 2005-09-01 + * Merged modified form of patch to avoid dlopen/dlclose by + the static libselinux from Dan Walsh. Users of the static libselinux + will not have any context translation by default. + +1.25.6 2005-08-31 + * Added public functions to export context translation to + users of libselinux (selinux_trans_to_raw_context, + selinux_raw_to_trans_context). + +1.25.5 2005-08-26 + * Remove special definition for context_range_set; use + common code. + +1.25.4 2005-08-25 + * Hid translation-related symbols entirely and ensured that + raw functions have hidden definitions for internal use. + * Allowed setting NULL via context_set* functions. + * Allowed whitespace in MLS component of context. + * Changed rpm_execcon to use translated functions to workaround + lack of MLS level on upgraded systems. + +1.25.3 2005-08-23 + * Merged context translation patch, originally by TCS, + with modifications by Dan Walsh (Red Hat). + +1.25.2 2005-08-11 + * Merged several fixes for error handling paths in the + AVC sidtab, matchpathcon, booleans, context, and get_context_list + code from Serge Hallyn (IBM). Bugs found by Coverity. + +1.25.1 2005-08-10 + * Removed setupns; migrated to pam. + * Merged patches to rename checkPasswdAccess() from Joshua Brindle. + Original symbol is temporarily retained for compatibility until + all callers are updated. + +1.24 2005-06-20 + * Updated version for release. + +1.23.12 2005-06-13 + * Merged security_setupns() from Chad Sellers. + +1.23.11 2005-05-19 + * Merged avcstat and selinux man page from Dan Walsh. + * Changed security_load_booleans to process booleans.local + even if booleans file doesn't exist. + +1.23.10 2005-04-29 + * Merged set_selinuxmnt patch from Bill Nottingham (Red Hat). + +1.23.9 2005-04-26 + * Rewrote get_ordered_context_list and helpers, including + changing logic to allow variable MLS fields. + +1.23.8 2005-04-25 + * Merged matchpathcon and man page patch from Dan Walsh. + +1.23.7 2005-04-12 + * Changed boolean functions to return -1 with errno ENOENT + rather than assert on a NULL selinux_mnt (i.e. selinuxfs not + mounted). + +1.23.6 2005-04-08 + * Fixed bug in matchpathcon_filespec_destroy. + +1.23.5 2005-04-05 + * Fixed bug in rpm_execcon error handling path. + +1.23.4 2005-04-04 + * Merged fix for set_matchpathcon* functions from Andreas Steinmetz. + * Merged fix for getconlist utility from Andreas Steinmetz. + +1.23.3 2005-03-29 + * Merged security_set_boolean_list patch from Dan Walsh. + This introduces booleans.local support for setsebool. + +1.23.2 2005-03-17 + * Merged destructors patch from Tomas Mraz. + +1.23.1 2005-03-16 + * Added set_matchpathcon_flags() function for setting flags + controlling operation of matchpathcon. MATCHPATHCON_BASEONLY + means only process the base file_contexts file, not + file_contexts.homedirs or file_contexts.local, and is for use by + setfiles -c. + * Updated matchpathcon.3 man page. + +1.22 2005-03-09 + * Updated version for release. + +1.21.13 2005-03-08 + * Fixed bug in matchpathcon_filespec_add() - failure to clear fl_head. + +1.21.12 2005-03-01 + * Changed matchpathcon_common to ignore any non-format bits in the mode. + +1.21.11 2005-02-22 + * Merged several fixes from Ulrich Drepper. + +1.21.10 2005-02-17 + * Merged matchpathcon patch for file_contexts.homedir from Dan Walsh. + * Added selinux_users_path() for path to directory containing + system.users and local.users. + +1.21.9 2005-02-09 + * Changed relabel Makefile target to use restorecon. + +1.21.8 2005-02-07 + * Regenerated av_permissions.h. + +1.21.7 2005-02-01 + * Modified avc_dump_av to explicitly check for any permissions that + cannot be mapped to string names and display them as a hex value. + +1.21.6 2005-01-31 + * Regenerated av_permissions.h. + +1.21.5 2005-01-28 + * Generalized matchpathcon internals, exported more interfaces, + and moved additional code from setfiles into libselinux so that + setfiles can directly use matchpathcon. + +1.21.4 2005-01-27 + * Prevent overflow of spec array in matchpathcon. + +1.21.3 2005-01-26 + * Fixed several uses of internal functions to avoid relocations. + * Changed rpm_execcon to check is_selinux_enabled() and fallback to + a regular execve if not enabled (or unable to determine due to a lack + of /proc, e.g. chroot'd environment). + + +1.21.2 2005-01-24 + * Merged minor fix for avcstat from Dan Walsh. + +1.21.1 2005-01-19 + * Merged patch from Dan Walsh, including: + - new is_context_customizable function + - changed matchpathcon to also use file_contexts.local if present + - man page cleanups + +1.20 2005-01-04 + * Changed matchpathcon to return -1 with errno ENOENT for + <<none>> entries, and also for an empty file_contexts configuration. + * Removed some trivial utils that were not useful or redundant. + * Changed BINDIR default to /usr/sbin to match change in Fedora. + * Added security_compute_member. + * Added man page for setcon. + * Merged more man pages from Dan Walsh. + * Merged avcstat from James Morris. + * Merged build fix for mips from Manoj Srivastava. + * Merged C++ support from John Ramsdell of MITRE. + * Merged setcon() function from Darrel Goeddel of TCS. + * Merged setsebool/togglesebool enhancement from Steve Grubb. + * Merged cleanup patches from Steve Grubb. + +1.18 2004-11-01 + * Merged cleanup patches from Steve Grubb. + * Added rpm_execcon. + * Merged setenforce and removable context patch from Dan Walsh. + * Merged build fix for alpha from Ulrich Drepper. + * Removed copyright/license from selinux_netlink.h - definitions only. + * Merged matchmediacon from Dan Walsh. + * Regenerated headers for new nscd permissions. + * Added get_default_context_with_role. + * Added set_matchpathcon_printf. + * Reworked av_inherit.h to allow easier re-use by kernel. + * Changed avc_has_perm_noaudit to not fail on netlink errors. + * Changed avc netlink code to check pid based on patch by Steve Grubb. + * Merged second optimization patch from Ulrich Drepper. + * Changed matchpathcon to skip invalid file_contexts entries. + * Made string tables private to libselinux. + * Merged strcat->stpcpy patch from Ulrich Drepper. + * Merged matchpathcon man page from Dan Walsh. + * Merged patch to eliminate PLTs for local syms from Ulrich Drepper. + * Autobind netlink socket. + * Dropped compatibility code from security_compute_user. + * Merged fix for context_range_set from Chad Hanson. + * Merged allocation failure checking patch from Chad Hanson. + * Merged avc netlink error message patch from Colin Walters. + +1.16 2004-08-19 + * Regenerated headers for nscd class. + * Merged man pages from Dan Walsh. + * Merged context_new bug fix for MLS ranges from Chad Hanson. + * Merged toggle_bool from Chris PeBenito, renamed to togglesebool. + * Renamed change_bool and show_bools to setsebool and getsebool. + * Merged security_load_booleans() function from Dan Walsh. + * Added selinux_booleans_path() function. + * Changed avc_init function prototype to use const. + * Regenerated headers for crontab permission. + * Added checkAccess from Dan Walsh. + * Merged getenforce patch from Dan Walsh. + * Regenerated headers for dbus classes. + +1.14 2004-06-16 + * Regenerated headers for fine-grained netlink classes. + * Merged selinux_config bug fix from Dan Walsh. + * Added userspace AVC man pages. + * Added man links for API calls to existing man pages documenting them. + * Replaced $HOME/.default_contexts support with /etc/selinux/contexts/users/$USER support. + * Merged patch to determine config file paths at runtime to support + reorganized layout. + * Regenerated flask headers with stable ordering. + * Merged patch for man pages from Russell Coker. + +1.12 2004-05-10 + * Updated flask files to include new SE-X security classes. + * Added security_disable function for runtime disable of SELinux prior + to initial policy load (for /sbin/init). + * Changed get_ordered_context_list to omit any reachable contexts + that are not explicitly listed in default_contexts, unless there + are no matches. + * Merged man pages from Russell Coker and Dan Walsh. + * Merged memory leak fixes from Dan Walsh. + * Merged policyvers errno patch from Chris PeBenito. + +1.10 2004-04-05 + * Merged getenforce patch from Dan Walsh. + * Fixed init_selinuxmnt to correctly handle use of "selinuxfs" as + the device specification, i.e. mount selinuxfs /selinux -t selinuxfs. + Based on a patch by Russell Coker. + * Merged matchpathcon buffer size fix from Dan Walsh. + +1.8 2004-03-09 + * Merged is_selinux_mls_enabled() from Chad Hanson of TCS. + * Added matchpathcon function. + * Updated userspace AVC to handle netlink selinux notifications. + +1.6 2004-02-18 + * Merged conditional policy extensions from Tresys Technology. + * Added userspace avc and SID table implementation. + * Fixed type on size in getpeercon per Thorsten Kukuk's advice. + * Fixed use of getpwnam_r per Thorsten Kukuk's advice. + * Changed to use getpwnam_r rather than getpwnam internally to + avoid clobbering any existing pwd struct obtained by the caller. + * Added getpeercon function to encapsulate getsockopt SO_PEERSEC + and handle allocation ala getfilecon. + * Changed is_selinux_enabled to return -1 on errors. + * Changed to discover selinuxfs mount point via /proc/mounts + so that the mount point can be changed without rebuilding. + +1.4 2003-12-01 + * Merged another cleanup patch from Bastian Blank and Joerg Hoh. + * Regenerate headers for new permissions. + * Merged static lib build patch from Bastian Blank and Joerg Hoh. + * Export SELINUXMNT definition, add SELINUXPOLICY definition. + * Add functions to provide access to enforce and policyvers. + * Changed is_selinux_enabled to check /proc/filesystems for selinuxfs. + * Fixed type for 'size' in *getfilecon. + * Dropped -lattr and changed #include's to <sys/xattr.h> + * Merged patch to move shared library to /lib from Dan Walsh. + * Changed get_ordered_context_list to support a failsafe context. + * Added selinuxenabled utility. + * Merged const patch from Thorsten Kukuk. + +1.2 2003-09-30 + * Change is_selinux_enabled to fail if policy isn't loaded. + * Changed Makefiles to allow non-root rpm builds. + * Added -lattr for libselinux.so to ensure proper binding. + +1.1 2003-08-13 + * Ensure that context strings are padded with a null byte + in case the kernel didn't include one. + * Regenerate headers, update helpers.c for code cleanup. + * Pass soname flag to linker (Colin Walters). + * Fixes for various items: add const as appropriate, handle missed OOM condition, clean up compile warnings (Colin Walters). + +1.0 2003-07-11 + * Initial public release.
diff --git a/selinux/libselinux/LICENSE b/selinux/libselinux/LICENSE new file mode 100644 index 0000000..d386268 --- /dev/null +++ b/selinux/libselinux/LICENSE
@@ -0,0 +1,21 @@ +This library (libselinux) is public domain software, i.e. not copyrighted. + +Warranty Exclusion +------------------ +You agree that this software is a +non-commercially developed program that may contain "bugs" (as that +term is used in the industry) and that it may not function as intended. +The software is licensed "as is". NSA makes no, and hereby expressly +disclaims all, warranties, express, implied, statutory, or otherwise +with respect to the software, including noninfringement and the implied +warranties of merchantability and fitness for a particular purpose. + +Limitation of Liability +----------------------- +In no event will NSA be liable for any damages, including loss of data, +lost profits, cost of cover, or other special, incidental, +consequential, direct or indirect damages arising from the software or +the use thereof, however caused and on any theory of liability. This +limitation will apply even if NSA has been advised of the possibility +of such damage. You acknowledge that this is a reasonable allocation of +risk.
diff --git a/selinux/libselinux/Makefile b/selinux/libselinux/Makefile new file mode 100644 index 0000000..6142b60 --- /dev/null +++ b/selinux/libselinux/Makefile
@@ -0,0 +1,47 @@ +SUBDIRS = src include utils man + +DISABLE_AVC ?= n +DISABLE_SETRANS ?= n +DISABLE_RPM ?= n +DISABLE_BOOL ?= n +ifeq ($(EMBEDDED),y) + override DISABLE_AVC=y + override DISABLE_SETRANS=y + override DISABLE_RPM=y + override DISABLE_BOOL=y +endif +ifeq ($(DISABLE_AVC),y) + EMFLAGS+= -DDISABLE_AVC +endif +ifeq ($(DISABLE_BOOL),y) + EMFLAGS+= -DDISABLE_BOOL +endif +ifeq ($(DISABLE_RPM),y) + EMFLAGS+= -DDISABLE_RPM +endif +ifeq ($(DISABLE_SETRANS),y) + EMFLAGS+= -DDISABLE_SETRANS +endif +export DISABLE_AVC DISABLE_SETRANS DISABLE_RPM DISABLE_BOOL EMFLAGS + +all install relabel clean distclean indent: + @for subdir in $(SUBDIRS); do \ + (cd $$subdir && $(MAKE) $@) || exit 1; \ + done + +swigify: all + $(MAKE) -C src swigify $@ + +pywrap: + $(MAKE) -C src pywrap $@ + +rubywrap: + $(MAKE) -C src rubywrap $@ + +install-pywrap: + $(MAKE) -C src install-pywrap $@ + +install-rubywrap: + $(MAKE) -C src install-rubywrap $@ + +test:
diff --git a/selinux/libselinux/VERSION b/selinux/libselinux/VERSION new file mode 100644 index 0000000..95e3ba8 --- /dev/null +++ b/selinux/libselinux/VERSION
@@ -0,0 +1 @@ +2.5
diff --git a/selinux/libselinux/include/Makefile b/selinux/libselinux/include/Makefile new file mode 100644 index 0000000..757a6c9 --- /dev/null +++ b/selinux/libselinux/include/Makefile
@@ -0,0 +1,18 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +INCDIR ?= $(PREFIX)/include/selinux + +all: + +install: all + test -d $(INCDIR) || install -m 755 -d $(INCDIR) + install -m 644 $(wildcard selinux/*.h) $(INCDIR) + +relabel: + +indent: + ../../scripts/Lindent $(wildcard selinux/*.h) + +distclean clean: + -rm -f selinux/*~ +
diff --git a/selinux/libselinux/include/selinux/av_permissions.h b/selinux/libselinux/include/selinux/av_permissions.h new file mode 100644 index 0000000..c1269af --- /dev/null +++ b/selinux/libselinux/include/selinux/av_permissions.h
@@ -0,0 +1,1029 @@ +#warning "Please remove any #include of this header in your source code." +#warning "Instead, use string_to_av_perm() to map the permission name to a value." + +/* This file is automatically generated. Do not edit. */ +#define COMMON_FILE__IOCTL 0x00000001UL +#define COMMON_FILE__READ 0x00000002UL +#define COMMON_FILE__WRITE 0x00000004UL +#define COMMON_FILE__CREATE 0x00000008UL +#define COMMON_FILE__GETATTR 0x00000010UL +#define COMMON_FILE__SETATTR 0x00000020UL +#define COMMON_FILE__LOCK 0x00000040UL +#define COMMON_FILE__RELABELFROM 0x00000080UL +#define COMMON_FILE__RELABELTO 0x00000100UL +#define COMMON_FILE__APPEND 0x00000200UL +#define COMMON_FILE__UNLINK 0x00000400UL +#define COMMON_FILE__LINK 0x00000800UL +#define COMMON_FILE__RENAME 0x00001000UL +#define COMMON_FILE__EXECUTE 0x00002000UL +#define COMMON_FILE__SWAPON 0x00004000UL +#define COMMON_FILE__QUOTAON 0x00008000UL +#define COMMON_FILE__MOUNTON 0x00010000UL +#define COMMON_SOCKET__IOCTL 0x00000001UL +#define COMMON_SOCKET__READ 0x00000002UL +#define COMMON_SOCKET__WRITE 0x00000004UL +#define COMMON_SOCKET__CREATE 0x00000008UL +#define COMMON_SOCKET__GETATTR 0x00000010UL +#define COMMON_SOCKET__SETATTR 0x00000020UL +#define COMMON_SOCKET__LOCK 0x00000040UL +#define COMMON_SOCKET__RELABELFROM 0x00000080UL +#define COMMON_SOCKET__RELABELTO 0x00000100UL +#define COMMON_SOCKET__APPEND 0x00000200UL +#define COMMON_SOCKET__BIND 0x00000400UL +#define COMMON_SOCKET__CONNECT 0x00000800UL +#define COMMON_SOCKET__LISTEN 0x00001000UL +#define COMMON_SOCKET__ACCEPT 0x00002000UL +#define COMMON_SOCKET__GETOPT 0x00004000UL +#define COMMON_SOCKET__SETOPT 0x00008000UL +#define COMMON_SOCKET__SHUTDOWN 0x00010000UL +#define COMMON_SOCKET__RECVFROM 0x00020000UL +#define COMMON_SOCKET__SENDTO 0x00040000UL +#define COMMON_SOCKET__RECV_MSG 0x00080000UL +#define COMMON_SOCKET__SEND_MSG 0x00100000UL +#define COMMON_SOCKET__NAME_BIND 0x00200000UL +#define COMMON_IPC__CREATE 0x00000001UL +#define COMMON_IPC__DESTROY 0x00000002UL +#define COMMON_IPC__GETATTR 0x00000004UL +#define COMMON_IPC__SETATTR 0x00000008UL +#define COMMON_IPC__READ 0x00000010UL +#define COMMON_IPC__WRITE 0x00000020UL +#define COMMON_IPC__ASSOCIATE 0x00000040UL +#define COMMON_IPC__UNIX_READ 0x00000080UL +#define COMMON_IPC__UNIX_WRITE 0x00000100UL +#define COMMON_DATABASE__CREATE 0x00000001UL +#define COMMON_DATABASE__DROP 0x00000002UL +#define COMMON_DATABASE__GETATTR 0x00000004UL +#define COMMON_DATABASE__SETATTR 0x00000008UL +#define COMMON_DATABASE__RELABELFROM 0x00000010UL +#define COMMON_DATABASE__RELABELTO 0x00000020UL +#define FILESYSTEM__MOUNT 0x00000001UL +#define FILESYSTEM__REMOUNT 0x00000002UL +#define FILESYSTEM__UNMOUNT 0x00000004UL +#define FILESYSTEM__GETATTR 0x00000008UL +#define FILESYSTEM__RELABELFROM 0x00000010UL +#define FILESYSTEM__RELABELTO 0x00000020UL +#define FILESYSTEM__TRANSITION 0x00000040UL +#define FILESYSTEM__ASSOCIATE 0x00000080UL +#define FILESYSTEM__QUOTAMOD 0x00000100UL +#define FILESYSTEM__QUOTAGET 0x00000200UL +#define DIR__IOCTL 0x00000001UL +#define DIR__READ 0x00000002UL +#define DIR__WRITE 0x00000004UL +#define DIR__CREATE 0x00000008UL +#define DIR__GETATTR 0x00000010UL +#define DIR__SETATTR 0x00000020UL +#define DIR__LOCK 0x00000040UL +#define DIR__RELABELFROM 0x00000080UL +#define DIR__RELABELTO 0x00000100UL +#define DIR__APPEND 0x00000200UL +#define DIR__UNLINK 0x00000400UL +#define DIR__LINK 0x00000800UL +#define DIR__RENAME 0x00001000UL +#define DIR__EXECUTE 0x00002000UL +#define DIR__SWAPON 0x00004000UL +#define DIR__QUOTAON 0x00008000UL +#define DIR__MOUNTON 0x00010000UL +#define DIR__ADD_NAME 0x00020000UL +#define DIR__REMOVE_NAME 0x00040000UL +#define DIR__REPARENT 0x00080000UL +#define DIR__SEARCH 0x00100000UL +#define DIR__RMDIR 0x00200000UL +#define DIR__OPEN 0x00400000UL +#define FILE__IOCTL 0x00000001UL +#define FILE__READ 0x00000002UL +#define FILE__WRITE 0x00000004UL +#define FILE__CREATE 0x00000008UL +#define FILE__GETATTR 0x00000010UL +#define FILE__SETATTR 0x00000020UL +#define FILE__LOCK 0x00000040UL +#define FILE__RELABELFROM 0x00000080UL +#define FILE__RELABELTO 0x00000100UL +#define FILE__APPEND 0x00000200UL +#define FILE__UNLINK 0x00000400UL +#define FILE__LINK 0x00000800UL +#define FILE__RENAME 0x00001000UL +#define FILE__EXECUTE 0x00002000UL +#define FILE__SWAPON 0x00004000UL +#define FILE__QUOTAON 0x00008000UL +#define FILE__MOUNTON 0x00010000UL +#define FILE__EXECUTE_NO_TRANS 0x00020000UL +#define FILE__ENTRYPOINT 0x00040000UL +#define FILE__EXECMOD 0x00080000UL +#define FILE__OPEN 0x00100000UL +#define LNK_FILE__IOCTL 0x00000001UL +#define LNK_FILE__READ 0x00000002UL +#define LNK_FILE__WRITE 0x00000004UL +#define LNK_FILE__CREATE 0x00000008UL +#define LNK_FILE__GETATTR 0x00000010UL +#define LNK_FILE__SETATTR 0x00000020UL +#define LNK_FILE__LOCK 0x00000040UL +#define LNK_FILE__RELABELFROM 0x00000080UL +#define LNK_FILE__RELABELTO 0x00000100UL +#define LNK_FILE__APPEND 0x00000200UL +#define LNK_FILE__UNLINK 0x00000400UL +#define LNK_FILE__LINK 0x00000800UL +#define LNK_FILE__RENAME 0x00001000UL +#define LNK_FILE__EXECUTE 0x00002000UL +#define LNK_FILE__SWAPON 0x00004000UL +#define LNK_FILE__QUOTAON 0x00008000UL +#define LNK_FILE__MOUNTON 0x00010000UL +#define CHR_FILE__IOCTL 0x00000001UL +#define CHR_FILE__READ 0x00000002UL +#define CHR_FILE__WRITE 0x00000004UL +#define CHR_FILE__CREATE 0x00000008UL +#define CHR_FILE__GETATTR 0x00000010UL +#define CHR_FILE__SETATTR 0x00000020UL +#define CHR_FILE__LOCK 0x00000040UL +#define CHR_FILE__RELABELFROM 0x00000080UL +#define CHR_FILE__RELABELTO 0x00000100UL +#define CHR_FILE__APPEND 0x00000200UL +#define CHR_FILE__UNLINK 0x00000400UL +#define CHR_FILE__LINK 0x00000800UL +#define CHR_FILE__RENAME 0x00001000UL +#define CHR_FILE__EXECUTE 0x00002000UL +#define CHR_FILE__SWAPON 0x00004000UL +#define CHR_FILE__QUOTAON 0x00008000UL +#define CHR_FILE__MOUNTON 0x00010000UL +#define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL +#define CHR_FILE__ENTRYPOINT 0x00040000UL +#define CHR_FILE__EXECMOD 0x00080000UL +#define CHR_FILE__OPEN 0x00100000UL +#define BLK_FILE__IOCTL 0x00000001UL +#define BLK_FILE__READ 0x00000002UL +#define BLK_FILE__WRITE 0x00000004UL +#define BLK_FILE__CREATE 0x00000008UL +#define BLK_FILE__GETATTR 0x00000010UL +#define BLK_FILE__SETATTR 0x00000020UL +#define BLK_FILE__LOCK 0x00000040UL +#define BLK_FILE__RELABELFROM 0x00000080UL +#define BLK_FILE__RELABELTO 0x00000100UL +#define BLK_FILE__APPEND 0x00000200UL +#define BLK_FILE__UNLINK 0x00000400UL +#define BLK_FILE__LINK 0x00000800UL +#define BLK_FILE__RENAME 0x00001000UL +#define BLK_FILE__EXECUTE 0x00002000UL +#define BLK_FILE__SWAPON 0x00004000UL +#define BLK_FILE__QUOTAON 0x00008000UL +#define BLK_FILE__MOUNTON 0x00010000UL +#define BLK_FILE__OPEN 0x00020000UL +#define SOCK_FILE__IOCTL 0x00000001UL +#define SOCK_FILE__READ 0x00000002UL +#define SOCK_FILE__WRITE 0x00000004UL +#define SOCK_FILE__CREATE 0x00000008UL +#define SOCK_FILE__GETATTR 0x00000010UL +#define SOCK_FILE__SETATTR 0x00000020UL +#define SOCK_FILE__LOCK 0x00000040UL +#define SOCK_FILE__RELABELFROM 0x00000080UL +#define SOCK_FILE__RELABELTO 0x00000100UL +#define SOCK_FILE__APPEND 0x00000200UL +#define SOCK_FILE__UNLINK 0x00000400UL +#define SOCK_FILE__LINK 0x00000800UL +#define SOCK_FILE__RENAME 0x00001000UL +#define SOCK_FILE__EXECUTE 0x00002000UL +#define SOCK_FILE__SWAPON 0x00004000UL +#define SOCK_FILE__QUOTAON 0x00008000UL +#define SOCK_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__IOCTL 0x00000001UL +#define FIFO_FILE__READ 0x00000002UL +#define FIFO_FILE__WRITE 0x00000004UL +#define FIFO_FILE__CREATE 0x00000008UL +#define FIFO_FILE__GETATTR 0x00000010UL +#define FIFO_FILE__SETATTR 0x00000020UL +#define FIFO_FILE__LOCK 0x00000040UL +#define FIFO_FILE__RELABELFROM 0x00000080UL +#define FIFO_FILE__RELABELTO 0x00000100UL +#define FIFO_FILE__APPEND 0x00000200UL +#define FIFO_FILE__UNLINK 0x00000400UL +#define FIFO_FILE__LINK 0x00000800UL +#define FIFO_FILE__RENAME 0x00001000UL +#define FIFO_FILE__EXECUTE 0x00002000UL +#define FIFO_FILE__SWAPON 0x00004000UL +#define FIFO_FILE__QUOTAON 0x00008000UL +#define FIFO_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__OPEN 0x00020000UL +#define FD__USE 0x00000001UL +#define SOCKET__IOCTL 0x00000001UL +#define SOCKET__READ 0x00000002UL +#define SOCKET__WRITE 0x00000004UL +#define SOCKET__CREATE 0x00000008UL +#define SOCKET__GETATTR 0x00000010UL +#define SOCKET__SETATTR 0x00000020UL +#define SOCKET__LOCK 0x00000040UL +#define SOCKET__RELABELFROM 0x00000080UL +#define SOCKET__RELABELTO 0x00000100UL +#define SOCKET__APPEND 0x00000200UL +#define SOCKET__BIND 0x00000400UL +#define SOCKET__CONNECT 0x00000800UL +#define SOCKET__LISTEN 0x00001000UL +#define SOCKET__ACCEPT 0x00002000UL +#define SOCKET__GETOPT 0x00004000UL +#define SOCKET__SETOPT 0x00008000UL +#define SOCKET__SHUTDOWN 0x00010000UL +#define SOCKET__RECVFROM 0x00020000UL +#define SOCKET__SENDTO 0x00040000UL +#define SOCKET__RECV_MSG 0x00080000UL +#define SOCKET__SEND_MSG 0x00100000UL +#define SOCKET__NAME_BIND 0x00200000UL +#define TCP_SOCKET__IOCTL 0x00000001UL +#define TCP_SOCKET__READ 0x00000002UL +#define TCP_SOCKET__WRITE 0x00000004UL +#define TCP_SOCKET__CREATE 0x00000008UL +#define TCP_SOCKET__GETATTR 0x00000010UL +#define TCP_SOCKET__SETATTR 0x00000020UL +#define TCP_SOCKET__LOCK 0x00000040UL +#define TCP_SOCKET__RELABELFROM 0x00000080UL +#define TCP_SOCKET__RELABELTO 0x00000100UL +#define TCP_SOCKET__APPEND 0x00000200UL +#define TCP_SOCKET__BIND 0x00000400UL +#define TCP_SOCKET__CONNECT 0x00000800UL +#define TCP_SOCKET__LISTEN 0x00001000UL +#define TCP_SOCKET__ACCEPT 0x00002000UL +#define TCP_SOCKET__GETOPT 0x00004000UL +#define TCP_SOCKET__SETOPT 0x00008000UL +#define TCP_SOCKET__SHUTDOWN 0x00010000UL +#define TCP_SOCKET__RECVFROM 0x00020000UL +#define TCP_SOCKET__SENDTO 0x00040000UL +#define TCP_SOCKET__RECV_MSG 0x00080000UL +#define TCP_SOCKET__SEND_MSG 0x00100000UL +#define TCP_SOCKET__NAME_BIND 0x00200000UL +#define TCP_SOCKET__CONNECTTO 0x00400000UL +#define TCP_SOCKET__NEWCONN 0x00800000UL +#define TCP_SOCKET__ACCEPTFROM 0x01000000UL +#define TCP_SOCKET__NODE_BIND 0x02000000UL +#define TCP_SOCKET__NAME_CONNECT 0x04000000UL +#define UDP_SOCKET__IOCTL 0x00000001UL +#define UDP_SOCKET__READ 0x00000002UL +#define UDP_SOCKET__WRITE 0x00000004UL +#define UDP_SOCKET__CREATE 0x00000008UL +#define UDP_SOCKET__GETATTR 0x00000010UL +#define UDP_SOCKET__SETATTR 0x00000020UL +#define UDP_SOCKET__LOCK 0x00000040UL +#define UDP_SOCKET__RELABELFROM 0x00000080UL +#define UDP_SOCKET__RELABELTO 0x00000100UL +#define UDP_SOCKET__APPEND 0x00000200UL +#define UDP_SOCKET__BIND 0x00000400UL +#define UDP_SOCKET__CONNECT 0x00000800UL +#define UDP_SOCKET__LISTEN 0x00001000UL +#define UDP_SOCKET__ACCEPT 0x00002000UL +#define UDP_SOCKET__GETOPT 0x00004000UL +#define UDP_SOCKET__SETOPT 0x00008000UL +#define UDP_SOCKET__SHUTDOWN 0x00010000UL +#define UDP_SOCKET__RECVFROM 0x00020000UL +#define UDP_SOCKET__SENDTO 0x00040000UL +#define UDP_SOCKET__RECV_MSG 0x00080000UL +#define UDP_SOCKET__SEND_MSG 0x00100000UL +#define UDP_SOCKET__NAME_BIND 0x00200000UL +#define UDP_SOCKET__NODE_BIND 0x00400000UL +#define RAWIP_SOCKET__IOCTL 0x00000001UL +#define RAWIP_SOCKET__READ 0x00000002UL +#define RAWIP_SOCKET__WRITE 0x00000004UL +#define RAWIP_SOCKET__CREATE 0x00000008UL +#define RAWIP_SOCKET__GETATTR 0x00000010UL +#define RAWIP_SOCKET__SETATTR 0x00000020UL +#define RAWIP_SOCKET__LOCK 0x00000040UL +#define RAWIP_SOCKET__RELABELFROM 0x00000080UL +#define RAWIP_SOCKET__RELABELTO 0x00000100UL +#define RAWIP_SOCKET__APPEND 0x00000200UL +#define RAWIP_SOCKET__BIND 0x00000400UL +#define RAWIP_SOCKET__CONNECT 0x00000800UL +#define RAWIP_SOCKET__LISTEN 0x00001000UL +#define RAWIP_SOCKET__ACCEPT 0x00002000UL +#define RAWIP_SOCKET__GETOPT 0x00004000UL +#define RAWIP_SOCKET__SETOPT 0x00008000UL +#define RAWIP_SOCKET__SHUTDOWN 0x00010000UL +#define RAWIP_SOCKET__RECVFROM 0x00020000UL +#define RAWIP_SOCKET__SENDTO 0x00040000UL +#define RAWIP_SOCKET__RECV_MSG 0x00080000UL +#define RAWIP_SOCKET__SEND_MSG 0x00100000UL +#define RAWIP_SOCKET__NAME_BIND 0x00200000UL +#define RAWIP_SOCKET__NODE_BIND 0x00400000UL +#define NODE__TCP_RECV 0x00000001UL +#define NODE__TCP_SEND 0x00000002UL +#define NODE__UDP_RECV 0x00000004UL +#define NODE__UDP_SEND 0x00000008UL +#define NODE__RAWIP_RECV 0x00000010UL +#define NODE__RAWIP_SEND 0x00000020UL +#define NODE__ENFORCE_DEST 0x00000040UL +#define NODE__DCCP_RECV 0x00000080UL +#define NODE__DCCP_SEND 0x00000100UL +#define NODE__RECVFROM 0x00000200UL +#define NODE__SENDTO 0x00000400UL +#define NETIF__TCP_RECV 0x00000001UL +#define NETIF__TCP_SEND 0x00000002UL +#define NETIF__UDP_RECV 0x00000004UL +#define NETIF__UDP_SEND 0x00000008UL +#define NETIF__RAWIP_RECV 0x00000010UL +#define NETIF__RAWIP_SEND 0x00000020UL +#define NETIF__DCCP_RECV 0x00000040UL +#define NETIF__DCCP_SEND 0x00000080UL +#define NETIF__INGRESS 0x00000100UL +#define NETIF__EGRESS 0x00000200UL +#define NETLINK_SOCKET__IOCTL 0x00000001UL +#define NETLINK_SOCKET__READ 0x00000002UL +#define NETLINK_SOCKET__WRITE 0x00000004UL +#define NETLINK_SOCKET__CREATE 0x00000008UL +#define NETLINK_SOCKET__GETATTR 0x00000010UL +#define NETLINK_SOCKET__SETATTR 0x00000020UL +#define NETLINK_SOCKET__LOCK 0x00000040UL +#define NETLINK_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_SOCKET__APPEND 0x00000200UL +#define NETLINK_SOCKET__BIND 0x00000400UL +#define NETLINK_SOCKET__CONNECT 0x00000800UL +#define NETLINK_SOCKET__LISTEN 0x00001000UL +#define NETLINK_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_SOCKET__GETOPT 0x00004000UL +#define NETLINK_SOCKET__SETOPT 0x00008000UL +#define NETLINK_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_SOCKET__SENDTO 0x00040000UL +#define NETLINK_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_SOCKET__NAME_BIND 0x00200000UL +#define PACKET_SOCKET__IOCTL 0x00000001UL +#define PACKET_SOCKET__READ 0x00000002UL +#define PACKET_SOCKET__WRITE 0x00000004UL +#define PACKET_SOCKET__CREATE 0x00000008UL +#define PACKET_SOCKET__GETATTR 0x00000010UL +#define PACKET_SOCKET__SETATTR 0x00000020UL +#define PACKET_SOCKET__LOCK 0x00000040UL +#define PACKET_SOCKET__RELABELFROM 0x00000080UL +#define PACKET_SOCKET__RELABELTO 0x00000100UL +#define PACKET_SOCKET__APPEND 0x00000200UL +#define PACKET_SOCKET__BIND 0x00000400UL +#define PACKET_SOCKET__CONNECT 0x00000800UL +#define PACKET_SOCKET__LISTEN 0x00001000UL +#define PACKET_SOCKET__ACCEPT 0x00002000UL +#define PACKET_SOCKET__GETOPT 0x00004000UL +#define PACKET_SOCKET__SETOPT 0x00008000UL +#define PACKET_SOCKET__SHUTDOWN 0x00010000UL +#define PACKET_SOCKET__RECVFROM 0x00020000UL +#define PACKET_SOCKET__SENDTO 0x00040000UL +#define PACKET_SOCKET__RECV_MSG 0x00080000UL +#define PACKET_SOCKET__SEND_MSG 0x00100000UL +#define PACKET_SOCKET__NAME_BIND 0x00200000UL +#define KEY_SOCKET__IOCTL 0x00000001UL +#define KEY_SOCKET__READ 0x00000002UL +#define KEY_SOCKET__WRITE 0x00000004UL +#define KEY_SOCKET__CREATE 0x00000008UL +#define KEY_SOCKET__GETATTR 0x00000010UL +#define KEY_SOCKET__SETATTR 0x00000020UL +#define KEY_SOCKET__LOCK 0x00000040UL +#define KEY_SOCKET__RELABELFROM 0x00000080UL +#define KEY_SOCKET__RELABELTO 0x00000100UL +#define KEY_SOCKET__APPEND 0x00000200UL +#define KEY_SOCKET__BIND 0x00000400UL +#define KEY_SOCKET__CONNECT 0x00000800UL +#define KEY_SOCKET__LISTEN 0x00001000UL +#define KEY_SOCKET__ACCEPT 0x00002000UL +#define KEY_SOCKET__GETOPT 0x00004000UL +#define KEY_SOCKET__SETOPT 0x00008000UL +#define KEY_SOCKET__SHUTDOWN 0x00010000UL +#define KEY_SOCKET__RECVFROM 0x00020000UL +#define KEY_SOCKET__SENDTO 0x00040000UL +#define KEY_SOCKET__RECV_MSG 0x00080000UL +#define KEY_SOCKET__SEND_MSG 0x00100000UL +#define KEY_SOCKET__NAME_BIND 0x00200000UL +#define UNIX_STREAM_SOCKET__IOCTL 0x00000001UL +#define UNIX_STREAM_SOCKET__READ 0x00000002UL +#define UNIX_STREAM_SOCKET__WRITE 0x00000004UL +#define UNIX_STREAM_SOCKET__CREATE 0x00000008UL +#define UNIX_STREAM_SOCKET__GETATTR 0x00000010UL +#define UNIX_STREAM_SOCKET__SETATTR 0x00000020UL +#define UNIX_STREAM_SOCKET__LOCK 0x00000040UL +#define UNIX_STREAM_SOCKET__RELABELFROM 0x00000080UL +#define UNIX_STREAM_SOCKET__RELABELTO 0x00000100UL +#define UNIX_STREAM_SOCKET__APPEND 0x00000200UL +#define UNIX_STREAM_SOCKET__BIND 0x00000400UL +#define UNIX_STREAM_SOCKET__CONNECT 0x00000800UL +#define UNIX_STREAM_SOCKET__LISTEN 0x00001000UL +#define UNIX_STREAM_SOCKET__ACCEPT 0x00002000UL +#define UNIX_STREAM_SOCKET__GETOPT 0x00004000UL +#define UNIX_STREAM_SOCKET__SETOPT 0x00008000UL +#define UNIX_STREAM_SOCKET__SHUTDOWN 0x00010000UL +#define UNIX_STREAM_SOCKET__RECVFROM 0x00020000UL +#define UNIX_STREAM_SOCKET__SENDTO 0x00040000UL +#define UNIX_STREAM_SOCKET__RECV_MSG 0x00080000UL +#define UNIX_STREAM_SOCKET__SEND_MSG 0x00100000UL +#define UNIX_STREAM_SOCKET__NAME_BIND 0x00200000UL +#define UNIX_STREAM_SOCKET__CONNECTTO 0x00400000UL +#define UNIX_STREAM_SOCKET__NEWCONN 0x00800000UL +#define UNIX_STREAM_SOCKET__ACCEPTFROM 0x01000000UL +#define UNIX_DGRAM_SOCKET__IOCTL 0x00000001UL +#define UNIX_DGRAM_SOCKET__READ 0x00000002UL +#define UNIX_DGRAM_SOCKET__WRITE 0x00000004UL +#define UNIX_DGRAM_SOCKET__CREATE 0x00000008UL +#define UNIX_DGRAM_SOCKET__GETATTR 0x00000010UL +#define UNIX_DGRAM_SOCKET__SETATTR 0x00000020UL +#define UNIX_DGRAM_SOCKET__LOCK 0x00000040UL +#define UNIX_DGRAM_SOCKET__RELABELFROM 0x00000080UL +#define UNIX_DGRAM_SOCKET__RELABELTO 0x00000100UL +#define UNIX_DGRAM_SOCKET__APPEND 0x00000200UL +#define UNIX_DGRAM_SOCKET__BIND 0x00000400UL +#define UNIX_DGRAM_SOCKET__CONNECT 0x00000800UL +#define UNIX_DGRAM_SOCKET__LISTEN 0x00001000UL +#define UNIX_DGRAM_SOCKET__ACCEPT 0x00002000UL +#define UNIX_DGRAM_SOCKET__GETOPT 0x00004000UL +#define UNIX_DGRAM_SOCKET__SETOPT 0x00008000UL +#define UNIX_DGRAM_SOCKET__SHUTDOWN 0x00010000UL +#define UNIX_DGRAM_SOCKET__RECVFROM 0x00020000UL +#define UNIX_DGRAM_SOCKET__SENDTO 0x00040000UL +#define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL +#define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL +#define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL +#define PROCESS__FORK 0x00000001UL +#define PROCESS__TRANSITION 0x00000002UL +#define PROCESS__SIGCHLD 0x00000004UL +#define PROCESS__SIGKILL 0x00000008UL +#define PROCESS__SIGSTOP 0x00000010UL +#define PROCESS__SIGNULL 0x00000020UL +#define PROCESS__SIGNAL 0x00000040UL +#define PROCESS__PTRACE 0x00000080UL +#define PROCESS__GETSCHED 0x00000100UL +#define PROCESS__SETSCHED 0x00000200UL +#define PROCESS__GETSESSION 0x00000400UL +#define PROCESS__GETPGID 0x00000800UL +#define PROCESS__SETPGID 0x00001000UL +#define PROCESS__GETCAP 0x00002000UL +#define PROCESS__SETCAP 0x00004000UL +#define PROCESS__SHARE 0x00008000UL +#define PROCESS__GETATTR 0x00010000UL +#define PROCESS__SETEXEC 0x00020000UL +#define PROCESS__SETFSCREATE 0x00040000UL +#define PROCESS__NOATSECURE 0x00080000UL +#define PROCESS__SIGINH 0x00100000UL +#define PROCESS__SETRLIMIT 0x00200000UL +#define PROCESS__RLIMITINH 0x00400000UL +#define PROCESS__DYNTRANSITION 0x00800000UL +#define PROCESS__SETCURRENT 0x01000000UL +#define PROCESS__EXECMEM 0x02000000UL +#define PROCESS__EXECSTACK 0x04000000UL +#define PROCESS__EXECHEAP 0x08000000UL +#define PROCESS__SETKEYCREATE 0x10000000UL +#define PROCESS__SETSOCKCREATE 0x20000000UL +#define IPC__CREATE 0x00000001UL +#define IPC__DESTROY 0x00000002UL +#define IPC__GETATTR 0x00000004UL +#define IPC__SETATTR 0x00000008UL +#define IPC__READ 0x00000010UL +#define IPC__WRITE 0x00000020UL +#define IPC__ASSOCIATE 0x00000040UL +#define IPC__UNIX_READ 0x00000080UL +#define IPC__UNIX_WRITE 0x00000100UL +#define SEM__CREATE 0x00000001UL +#define SEM__DESTROY 0x00000002UL +#define SEM__GETATTR 0x00000004UL +#define SEM__SETATTR 0x00000008UL +#define SEM__READ 0x00000010UL +#define SEM__WRITE 0x00000020UL +#define SEM__ASSOCIATE 0x00000040UL +#define SEM__UNIX_READ 0x00000080UL +#define SEM__UNIX_WRITE 0x00000100UL +#define MSGQ__CREATE 0x00000001UL +#define MSGQ__DESTROY 0x00000002UL +#define MSGQ__GETATTR 0x00000004UL +#define MSGQ__SETATTR 0x00000008UL +#define MSGQ__READ 0x00000010UL +#define MSGQ__WRITE 0x00000020UL +#define MSGQ__ASSOCIATE 0x00000040UL +#define MSGQ__UNIX_READ 0x00000080UL +#define MSGQ__UNIX_WRITE 0x00000100UL +#define MSGQ__ENQUEUE 0x00000200UL +#define MSG__SEND 0x00000001UL +#define MSG__RECEIVE 0x00000002UL +#define SHM__CREATE 0x00000001UL +#define SHM__DESTROY 0x00000002UL +#define SHM__GETATTR 0x00000004UL +#define SHM__SETATTR 0x00000008UL +#define SHM__READ 0x00000010UL +#define SHM__WRITE 0x00000020UL +#define SHM__ASSOCIATE 0x00000040UL +#define SHM__UNIX_READ 0x00000080UL +#define SHM__UNIX_WRITE 0x00000100UL +#define SHM__LOCK 0x00000200UL +#define SECURITY__COMPUTE_AV 0x00000001UL +#define SECURITY__COMPUTE_CREATE 0x00000002UL +#define SECURITY__COMPUTE_MEMBER 0x00000004UL +#define SECURITY__CHECK_CONTEXT 0x00000008UL +#define SECURITY__LOAD_POLICY 0x00000010UL +#define SECURITY__COMPUTE_RELABEL 0x00000020UL +#define SECURITY__COMPUTE_USER 0x00000040UL +#define SECURITY__SETENFORCE 0x00000080UL +#define SECURITY__SETBOOL 0x00000100UL +#define SECURITY__SETSECPARAM 0x00000200UL +#define SECURITY__SETCHECKREQPROT 0x00000400UL +#define SYSTEM__IPC_INFO 0x00000001UL +#define SYSTEM__SYSLOG_READ 0x00000002UL +#define SYSTEM__SYSLOG_MOD 0x00000004UL +#define SYSTEM__SYSLOG_CONSOLE 0x00000008UL +#define CAPABILITY__CHOWN 0x00000001UL +#define CAPABILITY__DAC_OVERRIDE 0x00000002UL +#define CAPABILITY__DAC_READ_SEARCH 0x00000004UL +#define CAPABILITY__FOWNER 0x00000008UL +#define CAPABILITY__FSETID 0x00000010UL +#define CAPABILITY__KILL 0x00000020UL +#define CAPABILITY__SETGID 0x00000040UL +#define CAPABILITY__SETUID 0x00000080UL +#define CAPABILITY__SETPCAP 0x00000100UL +#define CAPABILITY__LINUX_IMMUTABLE 0x00000200UL +#define CAPABILITY__NET_BIND_SERVICE 0x00000400UL +#define CAPABILITY__NET_BROADCAST 0x00000800UL +#define CAPABILITY__NET_ADMIN 0x00001000UL +#define CAPABILITY__NET_RAW 0x00002000UL +#define CAPABILITY__IPC_LOCK 0x00004000UL +#define CAPABILITY__IPC_OWNER 0x00008000UL +#define CAPABILITY__SYS_MODULE 0x00010000UL +#define CAPABILITY__SYS_RAWIO 0x00020000UL +#define CAPABILITY__SYS_CHROOT 0x00040000UL +#define CAPABILITY__SYS_PTRACE 0x00080000UL +#define CAPABILITY__SYS_PACCT 0x00100000UL +#define CAPABILITY__SYS_ADMIN 0x00200000UL +#define CAPABILITY__SYS_BOOT 0x00400000UL +#define CAPABILITY__SYS_NICE 0x00800000UL +#define CAPABILITY__SYS_RESOURCE 0x01000000UL +#define CAPABILITY__SYS_TIME 0x02000000UL +#define CAPABILITY__SYS_TTY_CONFIG 0x04000000UL +#define CAPABILITY__MKNOD 0x08000000UL +#define CAPABILITY__LEASE 0x10000000UL +#define CAPABILITY__AUDIT_WRITE 0x20000000UL +#define CAPABILITY__AUDIT_CONTROL 0x40000000UL +#define CAPABILITY__SETFCAP 0x80000000UL +#define CAPABILITY2__MAC_OVERRIDE 0x00000001UL +#define CAPABILITY2__MAC_ADMIN 0x00000002UL +#define PASSWD__PASSWD 0x00000001UL +#define PASSWD__CHFN 0x00000002UL +#define PASSWD__CHSH 0x00000004UL +#define PASSWD__ROOTOK 0x00000008UL +#define PASSWD__CRONTAB 0x00000010UL +#define X_DRAWABLE__CREATE 0x00000001UL +#define X_DRAWABLE__DESTROY 0x00000002UL +#define X_DRAWABLE__READ 0x00000004UL +#define X_DRAWABLE__WRITE 0x00000008UL +#define X_DRAWABLE__BLEND 0x00000010UL +#define X_DRAWABLE__GETATTR 0x00000020UL +#define X_DRAWABLE__SETATTR 0x00000040UL +#define X_DRAWABLE__LIST_CHILD 0x00000080UL +#define X_DRAWABLE__ADD_CHILD 0x00000100UL +#define X_DRAWABLE__REMOVE_CHILD 0x00000200UL +#define X_DRAWABLE__LIST_PROPERTY 0x00000400UL +#define X_DRAWABLE__GET_PROPERTY 0x00000800UL +#define X_DRAWABLE__SET_PROPERTY 0x00001000UL +#define X_DRAWABLE__MANAGE 0x00002000UL +#define X_DRAWABLE__OVERRIDE 0x00004000UL +#define X_DRAWABLE__SHOW 0x00008000UL +#define X_DRAWABLE__HIDE 0x00010000UL +#define X_DRAWABLE__SEND 0x00020000UL +#define X_DRAWABLE__RECEIVE 0x00040000UL +#define X_SCREEN__GETATTR 0x00000001UL +#define X_SCREEN__SETATTR 0x00000002UL +#define X_SCREEN__HIDE_CURSOR 0x00000004UL +#define X_SCREEN__SHOW_CURSOR 0x00000008UL +#define X_SCREEN__SAVER_GETATTR 0x00000010UL +#define X_SCREEN__SAVER_SETATTR 0x00000020UL +#define X_SCREEN__SAVER_HIDE 0x00000040UL +#define X_SCREEN__SAVER_SHOW 0x00000080UL +#define X_GC__CREATE 0x00000001UL +#define X_GC__DESTROY 0x00000002UL +#define X_GC__GETATTR 0x00000004UL +#define X_GC__SETATTR 0x00000008UL +#define X_GC__USE 0x00000010UL +#define X_FONT__CREATE 0x00000001UL +#define X_FONT__DESTROY 0x00000002UL +#define X_FONT__GETATTR 0x00000004UL +#define X_FONT__ADD_GLYPH 0x00000008UL +#define X_FONT__REMOVE_GLYPH 0x00000010UL +#define X_FONT__USE 0x00000020UL +#define X_COLORMAP__CREATE 0x00000001UL +#define X_COLORMAP__DESTROY 0x00000002UL +#define X_COLORMAP__READ 0x00000004UL +#define X_COLORMAP__WRITE 0x00000008UL +#define X_COLORMAP__GETATTR 0x00000010UL +#define X_COLORMAP__ADD_COLOR 0x00000020UL +#define X_COLORMAP__REMOVE_COLOR 0x00000040UL +#define X_COLORMAP__INSTALL 0x00000080UL +#define X_COLORMAP__UNINSTALL 0x00000100UL +#define X_COLORMAP__USE 0x00000200UL +#define X_PROPERTY__CREATE 0x00000001UL +#define X_PROPERTY__DESTROY 0x00000002UL +#define X_PROPERTY__READ 0x00000004UL +#define X_PROPERTY__WRITE 0x00000008UL +#define X_PROPERTY__APPEND 0x00000010UL +#define X_PROPERTY__GETATTR 0x00000020UL +#define X_PROPERTY__SETATTR 0x00000040UL +#define X_SELECTION__READ 0x00000001UL +#define X_SELECTION__WRITE 0x00000002UL +#define X_SELECTION__GETATTR 0x00000004UL +#define X_SELECTION__SETATTR 0x00000008UL +#define X_CURSOR__CREATE 0x00000001UL +#define X_CURSOR__DESTROY 0x00000002UL +#define X_CURSOR__READ 0x00000004UL +#define X_CURSOR__WRITE 0x00000008UL +#define X_CURSOR__GETATTR 0x00000010UL +#define X_CURSOR__SETATTR 0x00000020UL +#define X_CURSOR__USE 0x00000040UL +#define X_CLIENT__DESTROY 0x00000001UL +#define X_CLIENT__GETATTR 0x00000002UL +#define X_CLIENT__SETATTR 0x00000004UL +#define X_CLIENT__MANAGE 0x00000008UL +#define X_DEVICE__GETATTR 0x00000001UL +#define X_DEVICE__SETATTR 0x00000002UL +#define X_DEVICE__USE 0x00000004UL +#define X_DEVICE__READ 0x00000008UL +#define X_DEVICE__WRITE 0x00000010UL +#define X_DEVICE__GETFOCUS 0x00000020UL +#define X_DEVICE__SETFOCUS 0x00000040UL +#define X_DEVICE__BELL 0x00000080UL +#define X_DEVICE__FORCE_CURSOR 0x00000100UL +#define X_DEVICE__FREEZE 0x00000200UL +#define X_DEVICE__GRAB 0x00000400UL +#define X_DEVICE__MANAGE 0x00000800UL +#define X_SERVER__GETATTR 0x00000001UL +#define X_SERVER__SETATTR 0x00000002UL +#define X_SERVER__RECORD 0x00000004UL +#define X_SERVER__DEBUG 0x00000008UL +#define X_SERVER__GRAB 0x00000010UL +#define X_SERVER__MANAGE 0x00000020UL +#define X_EXTENSION__QUERY 0x00000001UL +#define X_EXTENSION__USE 0x00000002UL +#define X_RESOURCE__READ 0x00000001UL +#define X_RESOURCE__WRITE 0x00000002UL +#define X_EVENT__SEND 0x00000001UL +#define X_EVENT__RECEIVE 0x00000002UL +#define X_SYNTHETIC_EVENT__SEND 0x00000001UL +#define X_SYNTHETIC_EVENT__RECEIVE 0x00000002UL +#define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL +#define NETLINK_ROUTE_SOCKET__READ 0x00000002UL +#define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL +#define NETLINK_ROUTE_SOCKET__CREATE 0x00000008UL +#define NETLINK_ROUTE_SOCKET__GETATTR 0x00000010UL +#define NETLINK_ROUTE_SOCKET__SETATTR 0x00000020UL +#define NETLINK_ROUTE_SOCKET__LOCK 0x00000040UL +#define NETLINK_ROUTE_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_ROUTE_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_ROUTE_SOCKET__APPEND 0x00000200UL +#define NETLINK_ROUTE_SOCKET__BIND 0x00000400UL +#define NETLINK_ROUTE_SOCKET__CONNECT 0x00000800UL +#define NETLINK_ROUTE_SOCKET__LISTEN 0x00001000UL +#define NETLINK_ROUTE_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_ROUTE_SOCKET__GETOPT 0x00004000UL +#define NETLINK_ROUTE_SOCKET__SETOPT 0x00008000UL +#define NETLINK_ROUTE_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_ROUTE_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_ROUTE_SOCKET__SENDTO 0x00040000UL +#define NETLINK_ROUTE_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_ROUTE_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_ROUTE_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_ROUTE_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_ROUTE_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_FIREWALL_SOCKET__IOCTL 0x00000001UL +#define NETLINK_FIREWALL_SOCKET__READ 0x00000002UL +#define NETLINK_FIREWALL_SOCKET__WRITE 0x00000004UL +#define NETLINK_FIREWALL_SOCKET__CREATE 0x00000008UL +#define NETLINK_FIREWALL_SOCKET__GETATTR 0x00000010UL +#define NETLINK_FIREWALL_SOCKET__SETATTR 0x00000020UL +#define NETLINK_FIREWALL_SOCKET__LOCK 0x00000040UL +#define NETLINK_FIREWALL_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_FIREWALL_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_FIREWALL_SOCKET__APPEND 0x00000200UL +#define NETLINK_FIREWALL_SOCKET__BIND 0x00000400UL +#define NETLINK_FIREWALL_SOCKET__CONNECT 0x00000800UL +#define NETLINK_FIREWALL_SOCKET__LISTEN 0x00001000UL +#define NETLINK_FIREWALL_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_FIREWALL_SOCKET__GETOPT 0x00004000UL +#define NETLINK_FIREWALL_SOCKET__SETOPT 0x00008000UL +#define NETLINK_FIREWALL_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_FIREWALL_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_FIREWALL_SOCKET__SENDTO 0x00040000UL +#define NETLINK_FIREWALL_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_FIREWALL_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_FIREWALL_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_FIREWALL_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_FIREWALL_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_TCPDIAG_SOCKET__IOCTL 0x00000001UL +#define NETLINK_TCPDIAG_SOCKET__READ 0x00000002UL +#define NETLINK_TCPDIAG_SOCKET__WRITE 0x00000004UL +#define NETLINK_TCPDIAG_SOCKET__CREATE 0x00000008UL +#define NETLINK_TCPDIAG_SOCKET__GETATTR 0x00000010UL +#define NETLINK_TCPDIAG_SOCKET__SETATTR 0x00000020UL +#define NETLINK_TCPDIAG_SOCKET__LOCK 0x00000040UL +#define NETLINK_TCPDIAG_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_TCPDIAG_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_TCPDIAG_SOCKET__APPEND 0x00000200UL +#define NETLINK_TCPDIAG_SOCKET__BIND 0x00000400UL +#define NETLINK_TCPDIAG_SOCKET__CONNECT 0x00000800UL +#define NETLINK_TCPDIAG_SOCKET__LISTEN 0x00001000UL +#define NETLINK_TCPDIAG_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_TCPDIAG_SOCKET__GETOPT 0x00004000UL +#define NETLINK_TCPDIAG_SOCKET__SETOPT 0x00008000UL +#define NETLINK_TCPDIAG_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_TCPDIAG_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_TCPDIAG_SOCKET__SENDTO 0x00040000UL +#define NETLINK_TCPDIAG_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_TCPDIAG_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_TCPDIAG_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_TCPDIAG_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_NFLOG_SOCKET__IOCTL 0x00000001UL +#define NETLINK_NFLOG_SOCKET__READ 0x00000002UL +#define NETLINK_NFLOG_SOCKET__WRITE 0x00000004UL +#define NETLINK_NFLOG_SOCKET__CREATE 0x00000008UL +#define NETLINK_NFLOG_SOCKET__GETATTR 0x00000010UL +#define NETLINK_NFLOG_SOCKET__SETATTR 0x00000020UL +#define NETLINK_NFLOG_SOCKET__LOCK 0x00000040UL +#define NETLINK_NFLOG_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_NFLOG_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_NFLOG_SOCKET__APPEND 0x00000200UL +#define NETLINK_NFLOG_SOCKET__BIND 0x00000400UL +#define NETLINK_NFLOG_SOCKET__CONNECT 0x00000800UL +#define NETLINK_NFLOG_SOCKET__LISTEN 0x00001000UL +#define NETLINK_NFLOG_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_NFLOG_SOCKET__GETOPT 0x00004000UL +#define NETLINK_NFLOG_SOCKET__SETOPT 0x00008000UL +#define NETLINK_NFLOG_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_NFLOG_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_NFLOG_SOCKET__SENDTO 0x00040000UL +#define NETLINK_NFLOG_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_NFLOG_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_NFLOG_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_XFRM_SOCKET__IOCTL 0x00000001UL +#define NETLINK_XFRM_SOCKET__READ 0x00000002UL +#define NETLINK_XFRM_SOCKET__WRITE 0x00000004UL +#define NETLINK_XFRM_SOCKET__CREATE 0x00000008UL +#define NETLINK_XFRM_SOCKET__GETATTR 0x00000010UL +#define NETLINK_XFRM_SOCKET__SETATTR 0x00000020UL +#define NETLINK_XFRM_SOCKET__LOCK 0x00000040UL +#define NETLINK_XFRM_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_XFRM_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_XFRM_SOCKET__APPEND 0x00000200UL +#define NETLINK_XFRM_SOCKET__BIND 0x00000400UL +#define NETLINK_XFRM_SOCKET__CONNECT 0x00000800UL +#define NETLINK_XFRM_SOCKET__LISTEN 0x00001000UL +#define NETLINK_XFRM_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_XFRM_SOCKET__GETOPT 0x00004000UL +#define NETLINK_XFRM_SOCKET__SETOPT 0x00008000UL +#define NETLINK_XFRM_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_XFRM_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_XFRM_SOCKET__SENDTO 0x00040000UL +#define NETLINK_XFRM_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_XFRM_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_XFRM_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_XFRM_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_XFRM_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_SELINUX_SOCKET__IOCTL 0x00000001UL +#define NETLINK_SELINUX_SOCKET__READ 0x00000002UL +#define NETLINK_SELINUX_SOCKET__WRITE 0x00000004UL +#define NETLINK_SELINUX_SOCKET__CREATE 0x00000008UL +#define NETLINK_SELINUX_SOCKET__GETATTR 0x00000010UL +#define NETLINK_SELINUX_SOCKET__SETATTR 0x00000020UL +#define NETLINK_SELINUX_SOCKET__LOCK 0x00000040UL +#define NETLINK_SELINUX_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_SELINUX_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_SELINUX_SOCKET__APPEND 0x00000200UL +#define NETLINK_SELINUX_SOCKET__BIND 0x00000400UL +#define NETLINK_SELINUX_SOCKET__CONNECT 0x00000800UL +#define NETLINK_SELINUX_SOCKET__LISTEN 0x00001000UL +#define NETLINK_SELINUX_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_SELINUX_SOCKET__GETOPT 0x00004000UL +#define NETLINK_SELINUX_SOCKET__SETOPT 0x00008000UL +#define NETLINK_SELINUX_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_SELINUX_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_SELINUX_SOCKET__SENDTO 0x00040000UL +#define NETLINK_SELINUX_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_SELINUX_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_SELINUX_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_AUDIT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_AUDIT_SOCKET__READ 0x00000002UL +#define NETLINK_AUDIT_SOCKET__WRITE 0x00000004UL +#define NETLINK_AUDIT_SOCKET__CREATE 0x00000008UL +#define NETLINK_AUDIT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_AUDIT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_AUDIT_SOCKET__LOCK 0x00000040UL +#define NETLINK_AUDIT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_AUDIT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_AUDIT_SOCKET__APPEND 0x00000200UL +#define NETLINK_AUDIT_SOCKET__BIND 0x00000400UL +#define NETLINK_AUDIT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_AUDIT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_AUDIT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_AUDIT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_AUDIT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_AUDIT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_AUDIT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_AUDIT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_AUDIT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_AUDIT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_AUDIT_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY 0x01000000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV 0x02000000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT 0x04000000UL +#define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL +#define NETLINK_IP6FW_SOCKET__READ 0x00000002UL +#define NETLINK_IP6FW_SOCKET__WRITE 0x00000004UL +#define NETLINK_IP6FW_SOCKET__CREATE 0x00000008UL +#define NETLINK_IP6FW_SOCKET__GETATTR 0x00000010UL +#define NETLINK_IP6FW_SOCKET__SETATTR 0x00000020UL +#define NETLINK_IP6FW_SOCKET__LOCK 0x00000040UL +#define NETLINK_IP6FW_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_IP6FW_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_IP6FW_SOCKET__APPEND 0x00000200UL +#define NETLINK_IP6FW_SOCKET__BIND 0x00000400UL +#define NETLINK_IP6FW_SOCKET__CONNECT 0x00000800UL +#define NETLINK_IP6FW_SOCKET__LISTEN 0x00001000UL +#define NETLINK_IP6FW_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_IP6FW_SOCKET__GETOPT 0x00004000UL +#define NETLINK_IP6FW_SOCKET__SETOPT 0x00008000UL +#define NETLINK_IP6FW_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_IP6FW_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_IP6FW_SOCKET__SENDTO 0x00040000UL +#define NETLINK_IP6FW_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_IP6FW_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_IP6FW_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_IP6FW_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_IP6FW_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_DNRT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_DNRT_SOCKET__READ 0x00000002UL +#define NETLINK_DNRT_SOCKET__WRITE 0x00000004UL +#define NETLINK_DNRT_SOCKET__CREATE 0x00000008UL +#define NETLINK_DNRT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_DNRT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_DNRT_SOCKET__LOCK 0x00000040UL +#define NETLINK_DNRT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_DNRT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_DNRT_SOCKET__APPEND 0x00000200UL +#define NETLINK_DNRT_SOCKET__BIND 0x00000400UL +#define NETLINK_DNRT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_DNRT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_DNRT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_DNRT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_DNRT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_DNRT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_DNRT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_DNRT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_DNRT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_DNRT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_DNRT_SOCKET__NAME_BIND 0x00200000UL +#define DBUS__ACQUIRE_SVC 0x00000001UL +#define DBUS__SEND_MSG 0x00000002UL +#define NSCD__GETPWD 0x00000001UL +#define NSCD__GETGRP 0x00000002UL +#define NSCD__GETHOST 0x00000004UL +#define NSCD__GETSTAT 0x00000008UL +#define NSCD__ADMIN 0x00000010UL +#define NSCD__SHMEMPWD 0x00000020UL +#define NSCD__SHMEMGRP 0x00000040UL +#define NSCD__SHMEMHOST 0x00000080UL +#define NSCD__GETSERV 0x00000100UL +#define NSCD__SHMEMSERV 0x00000200UL +#define ASSOCIATION__SENDTO 0x00000001UL +#define ASSOCIATION__RECVFROM 0x00000002UL +#define ASSOCIATION__SETCONTEXT 0x00000004UL +#define ASSOCIATION__POLMATCH 0x00000008UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__WRITE 0x00000004UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__CREATE 0x00000008UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__LOCK 0x00000040UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__APPEND 0x00000200UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__BIND 0x00000400UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND 0x00200000UL +#define APPLETALK_SOCKET__IOCTL 0x00000001UL +#define APPLETALK_SOCKET__READ 0x00000002UL +#define APPLETALK_SOCKET__WRITE 0x00000004UL +#define APPLETALK_SOCKET__CREATE 0x00000008UL +#define APPLETALK_SOCKET__GETATTR 0x00000010UL +#define APPLETALK_SOCKET__SETATTR 0x00000020UL +#define APPLETALK_SOCKET__LOCK 0x00000040UL +#define APPLETALK_SOCKET__RELABELFROM 0x00000080UL +#define APPLETALK_SOCKET__RELABELTO 0x00000100UL +#define APPLETALK_SOCKET__APPEND 0x00000200UL +#define APPLETALK_SOCKET__BIND 0x00000400UL +#define APPLETALK_SOCKET__CONNECT 0x00000800UL +#define APPLETALK_SOCKET__LISTEN 0x00001000UL +#define APPLETALK_SOCKET__ACCEPT 0x00002000UL +#define APPLETALK_SOCKET__GETOPT 0x00004000UL +#define APPLETALK_SOCKET__SETOPT 0x00008000UL +#define APPLETALK_SOCKET__SHUTDOWN 0x00010000UL +#define APPLETALK_SOCKET__RECVFROM 0x00020000UL +#define APPLETALK_SOCKET__SENDTO 0x00040000UL +#define APPLETALK_SOCKET__RECV_MSG 0x00080000UL +#define APPLETALK_SOCKET__SEND_MSG 0x00100000UL +#define APPLETALK_SOCKET__NAME_BIND 0x00200000UL +#define PACKET__SEND 0x00000001UL +#define PACKET__RECV 0x00000002UL +#define PACKET__RELABELTO 0x00000004UL +#define PACKET__FLOW_IN 0x00000008UL +#define PACKET__FLOW_OUT 0x00000010UL +#define PACKET__FORWARD_IN 0x00000020UL +#define PACKET__FORWARD_OUT 0x00000040UL +#define KEY__VIEW 0x00000001UL +#define KEY__READ 0x00000002UL +#define KEY__WRITE 0x00000004UL +#define KEY__SEARCH 0x00000008UL +#define KEY__LINK 0x00000010UL +#define KEY__SETATTR 0x00000020UL +#define KEY__CREATE 0x00000040UL +#define CONTEXT__TRANSLATE 0x00000001UL +#define CONTEXT__CONTAINS 0x00000002UL +#define DCCP_SOCKET__IOCTL 0x00000001UL +#define DCCP_SOCKET__READ 0x00000002UL +#define DCCP_SOCKET__WRITE 0x00000004UL +#define DCCP_SOCKET__CREATE 0x00000008UL +#define DCCP_SOCKET__GETATTR 0x00000010UL +#define DCCP_SOCKET__SETATTR 0x00000020UL +#define DCCP_SOCKET__LOCK 0x00000040UL +#define DCCP_SOCKET__RELABELFROM 0x00000080UL +#define DCCP_SOCKET__RELABELTO 0x00000100UL +#define DCCP_SOCKET__APPEND 0x00000200UL +#define DCCP_SOCKET__BIND 0x00000400UL +#define DCCP_SOCKET__CONNECT 0x00000800UL +#define DCCP_SOCKET__LISTEN 0x00001000UL +#define DCCP_SOCKET__ACCEPT 0x00002000UL +#define DCCP_SOCKET__GETOPT 0x00004000UL +#define DCCP_SOCKET__SETOPT 0x00008000UL +#define DCCP_SOCKET__SHUTDOWN 0x00010000UL +#define DCCP_SOCKET__RECVFROM 0x00020000UL +#define DCCP_SOCKET__SENDTO 0x00040000UL +#define DCCP_SOCKET__RECV_MSG 0x00080000UL +#define DCCP_SOCKET__SEND_MSG 0x00100000UL +#define DCCP_SOCKET__NAME_BIND 0x00200000UL +#define DCCP_SOCKET__NODE_BIND 0x00400000UL +#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL +#define MEMPROTECT__MMAP_ZERO 0x00000001UL +#define DB_DATABASE__CREATE 0x00000001UL +#define DB_DATABASE__DROP 0x00000002UL +#define DB_DATABASE__GETATTR 0x00000004UL +#define DB_DATABASE__SETATTR 0x00000008UL +#define DB_DATABASE__RELABELFROM 0x00000010UL +#define DB_DATABASE__RELABELTO 0x00000020UL +#define DB_DATABASE__ACCESS 0x00000040UL +#define DB_DATABASE__INSTALL_MODULE 0x00000080UL +#define DB_DATABASE__LOAD_MODULE 0x00000100UL +#define DB_DATABASE__GET_PARAM 0x00000200UL +#define DB_DATABASE__SET_PARAM 0x00000400UL +#define DB_TABLE__CREATE 0x00000001UL +#define DB_TABLE__DROP 0x00000002UL +#define DB_TABLE__GETATTR 0x00000004UL +#define DB_TABLE__SETATTR 0x00000008UL +#define DB_TABLE__RELABELFROM 0x00000010UL +#define DB_TABLE__RELABELTO 0x00000020UL +#define DB_TABLE__USE 0x00000040UL +#define DB_TABLE__SELECT 0x00000080UL +#define DB_TABLE__UPDATE 0x00000100UL +#define DB_TABLE__INSERT 0x00000200UL +#define DB_TABLE__DELETE 0x00000400UL +#define DB_TABLE__LOCK 0x00000800UL +#define DB_PROCEDURE__CREATE 0x00000001UL +#define DB_PROCEDURE__DROP 0x00000002UL +#define DB_PROCEDURE__GETATTR 0x00000004UL +#define DB_PROCEDURE__SETATTR 0x00000008UL +#define DB_PROCEDURE__RELABELFROM 0x00000010UL +#define DB_PROCEDURE__RELABELTO 0x00000020UL +#define DB_PROCEDURE__EXECUTE 0x00000040UL +#define DB_PROCEDURE__ENTRYPOINT 0x00000080UL +#define DB_COLUMN__CREATE 0x00000001UL +#define DB_COLUMN__DROP 0x00000002UL +#define DB_COLUMN__GETATTR 0x00000004UL +#define DB_COLUMN__SETATTR 0x00000008UL +#define DB_COLUMN__RELABELFROM 0x00000010UL +#define DB_COLUMN__RELABELTO 0x00000020UL +#define DB_COLUMN__USE 0x00000040UL +#define DB_COLUMN__SELECT 0x00000080UL +#define DB_COLUMN__UPDATE 0x00000100UL +#define DB_COLUMN__INSERT 0x00000200UL +#define DB_TUPLE__RELABELFROM 0x00000001UL +#define DB_TUPLE__RELABELTO 0x00000002UL +#define DB_TUPLE__USE 0x00000004UL +#define DB_TUPLE__SELECT 0x00000008UL +#define DB_TUPLE__UPDATE 0x00000010UL +#define DB_TUPLE__INSERT 0x00000020UL +#define DB_TUPLE__DELETE 0x00000040UL +#define DB_BLOB__CREATE 0x00000001UL +#define DB_BLOB__DROP 0x00000002UL +#define DB_BLOB__GETATTR 0x00000004UL +#define DB_BLOB__SETATTR 0x00000008UL +#define DB_BLOB__RELABELFROM 0x00000010UL +#define DB_BLOB__RELABELTO 0x00000020UL +#define DB_BLOB__READ 0x00000040UL +#define DB_BLOB__WRITE 0x00000080UL +#define DB_BLOB__IMPORT 0x00000100UL +#define DB_BLOB__EXPORT 0x00000200UL +#define PEER__RECV 0x00000001UL +#define X_APPLICATION_DATA__PASTE 0x00000001UL +#define X_APPLICATION_DATA__PASTE_AFTER_CONFIRM 0x00000002UL +#define X_APPLICATION_DATA__COPY 0x00000004UL
diff --git a/selinux/libselinux/include/selinux/avc.h b/selinux/libselinux/include/selinux/avc.h new file mode 100644 index 0000000..b4bc6f3 --- /dev/null +++ b/selinux/libselinux/include/selinux/avc.h
@@ -0,0 +1,511 @@ +/* + * Access vector cache interface for object managers. + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + */ +#ifndef _SELINUX_AVC_H_ +#define _SELINUX_AVC_H_ + +#include <stdint.h> +#include <errno.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SID format and operations + */ +struct security_id { + char * ctx; + unsigned int refcnt; +}; +typedef struct security_id *security_id_t; + +#define SECSID_WILD (security_id_t)NULL /* unspecified SID */ + +/** + * avc_sid_to_context - get copy of context corresponding to SID. + * @sid: input SID + * @ctx: pointer to context reference + * + * Return a copy of the security context corresponding to the input + * @sid in the memory referenced by @ctx. The caller is expected to + * free the context with freecon(). Return %0 on success, -%1 on + * failure, with @errno set to %ENOMEM if insufficient memory was + * available to make the copy, or %EINVAL if the input SID is invalid. + */ +int avc_sid_to_context(security_id_t sid, char ** ctx); +int avc_sid_to_context_raw(security_id_t sid, char ** ctx); + +/** + * avc_context_to_sid - get SID for context. + * @ctx: input security context + * @sid: pointer to SID reference + * + * Look up security context @ctx in SID table, making + * a new entry if @ctx is not found. Increment the + * reference counter for the SID. Store a pointer + * to the SID structure into the memory referenced by @sid, + * returning %0 on success or -%1 on error with @errno set. + */ +int avc_context_to_sid(const char * ctx, security_id_t * sid); +int avc_context_to_sid_raw(const char * ctx, security_id_t * sid); + +/** + * sidget - increment SID reference counter. + * @sid: SID reference + * + * Increment the reference counter for @sid, indicating that + * @sid is in use by an (additional) object. Return the + * new reference count, or zero if @sid is invalid (has zero + * reference count). Note that avc_context_to_sid() also + * increments reference counts. + */ +int sidget(security_id_t sid); + +/** + * sidput - decrement SID reference counter. + * @sid: SID reference + * + * Decrement the reference counter for @sid, indicating that + * a reference to @sid is no longer in use. Return the + * new reference count. When the reference count reaches + * zero, the SID is invalid, and avc_context_to_sid() must + * be called to obtain a new SID for the security context. + */ +int sidput(security_id_t sid); + +/** + * avc_get_initial_sid - get SID for an initial kernel security identifier + * @name: input name of initial kernel security identifier + * @sid: pointer to a SID reference + * + * Get the context for an initial kernel security identifier specified by + * @name using security_get_initial_context() and then call + * avc_context_to_sid() to get the corresponding SID. + */ +int avc_get_initial_sid(const char *name, security_id_t * sid); + +/* + * AVC entry + */ +struct avc_entry; +struct avc_entry_ref { + struct avc_entry *ae; +}; + +/** + * avc_entry_ref_init - initialize an AVC entry reference. + * @aeref: pointer to avc entry reference structure + * + * Use this macro to initialize an avc entry reference structure + * before first use. These structures are passed to avc_has_perm(), + * which stores cache entry references in them. They can increase + * performance on repeated queries. + */ +#define avc_entry_ref_init(aeref) ((aeref)->ae = NULL) + +/* + * User-provided callbacks for memory, auditing, and locking + */ + +/* These structures are passed by reference to avc_init(). Passing + * a NULL reference will cause the AVC to use a default. The default + * memory callbacks are malloc() and free(). The default logging method + * is to print on stderr. If no thread callbacks are passed, a separate + * listening thread won't be started for kernel policy change messages. + * If no locking callbacks are passed, no locking will take place. + */ +struct avc_memory_callback { + /* malloc() equivalent. */ + void *(*func_malloc) (size_t size); + /* free() equivalent. */ + void (*func_free) (void *ptr); + /* Note that these functions should set errno on failure. + If not, some avc routines may return -1 without errno set. */ +}; + +struct avc_log_callback { + /* log the printf-style format and arguments. */ + void +#ifdef __GNUC__ +__attribute__ ((format(printf, 1, 2))) +#endif + (*func_log) (const char *fmt, ...); + /* store a string representation of auditdata (corresponding + to the given security class) into msgbuf. */ + void (*func_audit) (void *auditdata, security_class_t cls, + char *msgbuf, size_t msgbufsize); +}; + +struct avc_thread_callback { + /* create and start a thread, returning an opaque pointer to it; + the thread should run the given function. */ + void *(*func_create_thread) (void (*run) (void)); + /* cancel a given thread and free its resources. */ + void (*func_stop_thread) (void *thread); +}; + +struct avc_lock_callback { + /* create a lock and return an opaque pointer to it. */ + void *(*func_alloc_lock) (void); + /* obtain a given lock, blocking if necessary. */ + void (*func_get_lock) (void *lock); + /* release a given lock. */ + void (*func_release_lock) (void *lock); + /* destroy a given lock (free memory, etc.) */ + void (*func_free_lock) (void *lock); +}; + +/* + * Available options + */ + +/* no-op option, useful for unused slots in an array of options */ +#define AVC_OPT_UNUSED 0 +/* override kernel enforcing mode (boolean value) */ +#define AVC_OPT_SETENFORCE 1 + +/* + * AVC operations + */ + +/** + * avc_init - Initialize the AVC. + * @msgprefix: prefix for log messages + * @mem_callbacks: user-supplied memory callbacks + * @log_callbacks: user-supplied logging callbacks + * @thread_callbacks: user-supplied threading callbacks + * @lock_callbacks: user-supplied locking callbacks + * + * Initialize the access vector cache. Return %0 on + * success or -%1 with @errno set on failure. + * If @msgprefix is NULL, use "uavc". If any callback + * structure references are NULL, use default methods + * for those callbacks (see the definition of the callback + * structures above). + */ +int avc_init(const char *msgprefix, + const struct avc_memory_callback *mem_callbacks, + const struct avc_log_callback *log_callbacks, + const struct avc_thread_callback *thread_callbacks, + const struct avc_lock_callback *lock_callbacks); + +/** + * avc_open - Initialize the AVC. + * @opts: array of selabel_opt structures specifying AVC options or NULL. + * @nopts: number of elements in opts array or zero for no options. + * + * This function is identical to avc_init(), except the message prefix + * is set to "avc" and any callbacks desired should be specified via + * selinux_set_callback(). Available options are listed above. + */ +int avc_open(struct selinux_opt *opts, unsigned nopts); + +/** + * avc_cleanup - Remove unused SIDs and AVC entries. + * + * Search the SID table for SID structures with zero + * reference counts, and remove them along with all + * AVC entries that reference them. This can be used + * to return memory to the system. + */ +void avc_cleanup(void); + +/** + * avc_reset - Flush the cache and reset statistics. + * + * Remove all entries from the cache and reset all access + * statistics (as returned by avc_cache_stats()) to zero. + * The SID mapping is not affected. Return %0 on success, + * -%1 with @errno set on error. + */ +int avc_reset(void); + +/** + * avc_destroy - Free all AVC structures. + * + * Destroy all AVC structures and free all allocated + * memory. User-supplied locking, memory, and audit + * callbacks will be retained, but security-event + * callbacks will not. All SID's will be invalidated. + * User must call avc_init() if further use of AVC is desired. + */ +void avc_destroy(void); + +/** + * avc_has_perm_noaudit - Check permissions but perform no auditing. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @avd: access vector decisions + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions, and return a copy of the decisions + * in @avd. Return %0 if all @requested permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied, or to another value + * upon other errors. This function is typically called by avc_has_perm(), + * but may also be called directly to separate permission checking from + * auditing, e.g. in cases where a lock must be held for the check but + * should be released for the auditing. + */ +int avc_has_perm_noaudit(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, struct av_decision *avd); + +/** + * avc_has_perm - Check permissions and perform any appropriate auditing. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @auditdata: auxiliary audit data + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions. Audit the granting or denial of + * permissions in accordance with the policy. Return %0 if all @requested + * permissions are granted, -%1 with @errno set to %EACCES if any permissions + * are denied or to another value upon other errors. + */ +int avc_has_perm(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata); + +/** + * avc_audit - Audit the granting or denial of permissions. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions + * @avd: access vector decisions + * @result: result from avc_has_perm_noaudit + * @auditdata: auxiliary audit data + * + * Audit the granting or denial of permissions in accordance + * with the policy. This function is typically called by + * avc_has_perm() after a permission check, but can also be + * called directly by callers who use avc_has_perm_noaudit() + * in order to separate the permission check from the auditing. + * For example, this separation is useful when the permission check must + * be performed under a lock, to allow the lock to be released + * before calling the auditing code. + */ +void avc_audit(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct av_decision *avd, int result, void *auditdata); + +/** + * avc_compute_create - Compute SID for labeling a new object. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @newsid: pointer to SID reference + * + * Call the security server to obtain a context for labeling a + * new object. Look up the context in the SID table, making + * a new entry if not found. Increment the reference counter + * for the SID. Store a pointer to the SID structure into the + * memory referenced by @newsid, returning %0 on success or -%1 on + * error with @errno set. + */ +int avc_compute_create(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, security_id_t * newsid); + +/** + * avc_compute_member - Compute SID for polyinstantation. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @newsid: pointer to SID reference + * + * Call the security server to obtain a context for labeling an + * object instance. Look up the context in the SID table, making + * a new entry if not found. Increment the reference counter + * for the SID. Store a pointer to the SID structure into the + * memory referenced by @newsid, returning %0 on success or -%1 on + * error with @errno set. + */ +int avc_compute_member(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, security_id_t * newsid); + +/* + * security event callback facility + */ + +/* security events */ +#define AVC_CALLBACK_GRANT 1 +#define AVC_CALLBACK_TRY_REVOKE 2 +#define AVC_CALLBACK_REVOKE 4 +#define AVC_CALLBACK_RESET 8 +#define AVC_CALLBACK_AUDITALLOW_ENABLE 16 +#define AVC_CALLBACK_AUDITALLOW_DISABLE 32 +#define AVC_CALLBACK_AUDITDENY_ENABLE 64 +#define AVC_CALLBACK_AUDITDENY_DISABLE 128 + +/** + * avc_add_callback - Register a callback for security events. + * @callback: callback function + * @events: bitwise OR of desired security events + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions + * + * Register a callback function for events in the set @events + * related to the SID pair (@ssid, @tsid) and + * and the permissions @perms, interpreting + * @perms based on @tclass. Returns %0 on success or + * -%1 if insufficient memory exists to add the callback. + */ +int avc_add_callback(int (*callback) + (uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms, + access_vector_t * out_retained), + uint32_t events, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms); + +/* + * AVC statistics + */ + +/* If set, cache statistics are tracked. This may + * become a compile-time option in the future. + */ +#define AVC_CACHE_STATS 1 + +struct avc_cache_stats { + unsigned entry_lookups; + unsigned entry_hits; + unsigned entry_misses; + unsigned entry_discards; + unsigned cav_lookups; + unsigned cav_hits; + unsigned cav_probes; + unsigned cav_misses; +}; + +/** + * avc_cache_stats - get cache access statistics. + * @stats: reference to statistics structure + * + * Fill the supplied structure with information about AVC + * activity since the last call to avc_init() or + * avc_reset(). See the structure definition for + * details. + */ +void avc_cache_stats(struct avc_cache_stats *stats); + +/** + * avc_av_stats - log av table statistics. + * + * Log a message with information about the size and + * distribution of the access vector table. The audit + * callback is used to print the message. + */ +void avc_av_stats(void); + +/** + * avc_sid_stats - log SID table statistics. + * + * Log a message with information about the size and + * distribution of the SID table. The audit callback + * is used to print the message. + */ +void avc_sid_stats(void); + +/** + * avc_netlink_open - Create a netlink socket and connect to the kernel. + */ +int avc_netlink_open(int blocking); + +/** + * avc_netlink_loop - Wait for netlink messages from the kernel + */ +void avc_netlink_loop(void); + +/** + * avc_netlink_close - Close the netlink socket + */ +void avc_netlink_close(void); + +/** + * avc_netlink_acquire_fd - Acquire netlink socket fd. + * + * Allows the application to manage messages from the netlink socket in + * its own main loop. + */ +int avc_netlink_acquire_fd(void); + +/** + * avc_netlink_release_fd - Release netlink socket fd. + * + * Returns ownership of the netlink socket to the library. + */ +void avc_netlink_release_fd(void); + +/** + * avc_netlink_check_nb - Check netlink socket for new messages. + * + * Called by the application when using avc_netlink_acquire_fd() to + * process kernel netlink events. + */ +int avc_netlink_check_nb(void); + +/** + * selinux_status_open - Open and map SELinux kernel status page + * + */ +int selinux_status_open(int fallback); + +/** + * selinux_status_close - Unmap and close SELinux kernel status page + * + */ +void selinux_status_close(void); + +/** + * selinux_status_updated - Inform us whether the kernel status has been updated + * + */ +int selinux_status_updated(void); + +/** + * selinux_status_getenforce - Get the enforce flag value + * + */ +int selinux_status_getenforce(void); + +/** + * selinux_status_policyload - Get the number of policy reloaded + * + */ +int selinux_status_policyload(void); + +/** + * selinux_status_deny_unknown - Get the behavior for undefined classes/permissions + * + */ +int selinux_status_deny_unknown(void); + +#ifdef __cplusplus +} +#endif +#endif /* _SELINUX_AVC_H_ */
diff --git a/selinux/libselinux/include/selinux/context.h b/selinux/libselinux/include/selinux/context.h new file mode 100644 index 0000000..949fb1e --- /dev/null +++ b/selinux/libselinux/include/selinux/context.h
@@ -0,0 +1,50 @@ +#ifndef _SELINUX_CONTEXT_H_ +#define _SELINUX_CONTEXT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Functions to deal with security contexts in user space. + */ + + typedef struct { + void *ptr; + } context_s_t; + + typedef context_s_t *context_t; + +/* Return a new context initialized to a context string */ + + extern context_t context_new(const char *); + +/* + * Return a pointer to the string value of the context_t + * Valid until the next call to context_str or context_free + * for the same context_t* + */ + + extern char *context_str(context_t); + +/* Free the storage used by a context */ + extern void context_free(context_t); + +/* Get a pointer to the string value of a context component */ + + extern const char *context_type_get(context_t); + extern const char *context_range_get(context_t); + extern const char *context_role_get(context_t); + extern const char *context_user_get(context_t); + +/* Set a context component. Returns nonzero if unsuccessful */ + + extern int context_type_set(context_t, const char *); + extern int context_range_set(context_t, const char *); + extern int context_role_set(context_t, const char *); + extern int context_user_set(context_t, const char *); + +#ifdef __cplusplus +} +#endif +#endif
diff --git a/selinux/libselinux/include/selinux/flask.h b/selinux/libselinux/include/selinux/flask.h new file mode 100644 index 0000000..8128223 --- /dev/null +++ b/selinux/libselinux/include/selinux/flask.h
@@ -0,0 +1,118 @@ +/* This file is automatically generated. Do not edit. */ +#ifndef _SELINUX_FLASK_H_ +#define _SELINUX_FLASK_H_ + +#warning "Please remove any #include's of this header in your source code." +#warning "Instead, use string_to_security_class() to map the class name to a value." + +/* + * Security object class definitions + */ +#define SECCLASS_SECURITY 1 +#define SECCLASS_PROCESS 2 +#define SECCLASS_SYSTEM 3 +#define SECCLASS_CAPABILITY 4 +#define SECCLASS_FILESYSTEM 5 +#define SECCLASS_FILE 6 +#define SECCLASS_DIR 7 +#define SECCLASS_FD 8 +#define SECCLASS_LNK_FILE 9 +#define SECCLASS_CHR_FILE 10 +#define SECCLASS_BLK_FILE 11 +#define SECCLASS_SOCK_FILE 12 +#define SECCLASS_FIFO_FILE 13 +#define SECCLASS_SOCKET 14 +#define SECCLASS_TCP_SOCKET 15 +#define SECCLASS_UDP_SOCKET 16 +#define SECCLASS_RAWIP_SOCKET 17 +#define SECCLASS_NODE 18 +#define SECCLASS_NETIF 19 +#define SECCLASS_NETLINK_SOCKET 20 +#define SECCLASS_PACKET_SOCKET 21 +#define SECCLASS_KEY_SOCKET 22 +#define SECCLASS_UNIX_STREAM_SOCKET 23 +#define SECCLASS_UNIX_DGRAM_SOCKET 24 +#define SECCLASS_SEM 25 +#define SECCLASS_MSG 26 +#define SECCLASS_MSGQ 27 +#define SECCLASS_SHM 28 +#define SECCLASS_IPC 29 +#define SECCLASS_PASSWD 30 +#define SECCLASS_X_DRAWABLE 31 +#define SECCLASS_X_SCREEN 32 +#define SECCLASS_X_GC 33 +#define SECCLASS_X_FONT 34 +#define SECCLASS_X_COLORMAP 35 +#define SECCLASS_X_PROPERTY 36 +#define SECCLASS_X_SELECTION 37 +#define SECCLASS_X_CURSOR 38 +#define SECCLASS_X_CLIENT 39 +#define SECCLASS_X_DEVICE 40 +#define SECCLASS_X_SERVER 41 +#define SECCLASS_X_EXTENSION 42 +#define SECCLASS_NETLINK_ROUTE_SOCKET 43 +#define SECCLASS_NETLINK_FIREWALL_SOCKET 44 +#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45 +#define SECCLASS_NETLINK_NFLOG_SOCKET 46 +#define SECCLASS_NETLINK_XFRM_SOCKET 47 +#define SECCLASS_NETLINK_SELINUX_SOCKET 48 +#define SECCLASS_NETLINK_AUDIT_SOCKET 49 +#define SECCLASS_NETLINK_IP6FW_SOCKET 50 +#define SECCLASS_NETLINK_DNRT_SOCKET 51 +#define SECCLASS_DBUS 52 +#define SECCLASS_NSCD 53 +#define SECCLASS_ASSOCIATION 54 +#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 +#define SECCLASS_APPLETALK_SOCKET 56 +#define SECCLASS_PACKET 57 +#define SECCLASS_KEY 58 +#define SECCLASS_CONTEXT 59 +#define SECCLASS_DCCP_SOCKET 60 +#define SECCLASS_MEMPROTECT 61 +#define SECCLASS_DB_DATABASE 62 +#define SECCLASS_DB_TABLE 63 +#define SECCLASS_DB_PROCEDURE 64 +#define SECCLASS_DB_COLUMN 65 +#define SECCLASS_DB_TUPLE 66 +#define SECCLASS_DB_BLOB 67 +#define SECCLASS_PEER 68 +#define SECCLASS_CAPABILITY2 69 +#define SECCLASS_X_RESOURCE 70 +#define SECCLASS_X_EVENT 71 +#define SECCLASS_X_SYNTHETIC_EVENT 72 +#define SECCLASS_X_APPLICATION_DATA 73 + +/* + * Security identifier indices for initial entities + */ +#define SECINITSID_KERNEL 1 +#define SECINITSID_SECURITY 2 +#define SECINITSID_UNLABELED 3 +#define SECINITSID_FS 4 +#define SECINITSID_FILE 5 +#define SECINITSID_FILE_LABELS 6 +#define SECINITSID_INIT 7 +#define SECINITSID_ANY_SOCKET 8 +#define SECINITSID_PORT 9 +#define SECINITSID_NETIF 10 +#define SECINITSID_NETMSG 11 +#define SECINITSID_NODE 12 +#define SECINITSID_IGMP_PACKET 13 +#define SECINITSID_ICMP_SOCKET 14 +#define SECINITSID_TCP_SOCKET 15 +#define SECINITSID_SYSCTL_MODPROBE 16 +#define SECINITSID_SYSCTL 17 +#define SECINITSID_SYSCTL_FS 18 +#define SECINITSID_SYSCTL_KERNEL 19 +#define SECINITSID_SYSCTL_NET 20 +#define SECINITSID_SYSCTL_NET_UNIX 21 +#define SECINITSID_SYSCTL_VM 22 +#define SECINITSID_SYSCTL_DEV 23 +#define SECINITSID_KMOD 24 +#define SECINITSID_POLICY 25 +#define SECINITSID_SCMP_PACKET 26 +#define SECINITSID_DEVNULL 27 + +#define SECINITSID_NUM 27 + +#endif
diff --git a/selinux/libselinux/include/selinux/get_context_list.h b/selinux/libselinux/include/selinux/get_context_list.h new file mode 100644 index 0000000..8bd8f99 --- /dev/null +++ b/selinux/libselinux/include/selinux/get_context_list.h
@@ -0,0 +1,82 @@ +#ifndef _SELINUX_GET_SID_LIST_H_ +#define _SELINUX_GET_SID_LIST_H_ + +#include <selinux/selinux.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SELINUX_DEFAULTUSER "user_u" + +/* Get an ordered list of authorized security contexts for a user session + for 'user' spawned by 'fromcon' and set *conary to refer to the + NULL-terminated array of contexts. Every entry in the list will + be authorized by the policy, but the ordering is subject to user + customizable preferences. Returns number of entries in *conary. + If 'fromcon' is NULL, defaults to current context. + Caller must free via freeconary. */ + extern int get_ordered_context_list(const char *user, + char * fromcon, + char *** list); + +/* As above, but use the provided MLS level rather than the + default level for the user. */ + int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, + char *** list); + +/* Get the default security context for a user session for 'user' + spawned by 'fromcon' and set *newcon to refer to it. The context + will be one of those authorized by the policy, but the selection + of a default is subject to user customizable preferences. + If 'fromcon' is NULL, defaults to current context. + Returns 0 on success or -1 otherwise. + Caller must free via freecon. */ + extern int get_default_context(const char *user, + char * fromcon, + char ** newcon); + +/* As above, but use the provided MLS level rather than the + default level for the user. */ + int get_default_context_with_level(const char *user, + const char *level, + char * fromcon, + char ** newcon); + +/* Same as get_default_context, but only return a context + that has the specified role. If no reachable context exists + for the user with that role, then return -1. */ + int get_default_context_with_role(const char *user, + const char *role, + char * fromcon, + char ** newcon); + +/* Same as get_default_context, but only return a context + that has the specified role and level. If no reachable context exists + for the user with that role, then return -1. */ + int get_default_context_with_rolelevel(const char *user, + const char *level, + const char *role, + char * fromcon, + char ** newcon); + +/* Given a list of authorized security contexts for the user, + query the user to select one and set *newcon to refer to it. + Caller must free via freecon. + Returns 0 on sucess or -1 otherwise. */ + extern int query_user_context(char ** list, + char ** newcon); + +/* Allow the user to manually enter a context as a fallback + if a list of authorized contexts could not be obtained. + Caller must free via freecon. + Returns 0 on success or -1 otherwise. */ + extern int manual_user_enter_context(const char *user, + char ** newcon); + +#ifdef __cplusplus +} +#endif +#endif
diff --git a/selinux/libselinux/include/selinux/get_default_type.h b/selinux/libselinux/include/selinux/get_default_type.h new file mode 100644 index 0000000..65c5dd4 --- /dev/null +++ b/selinux/libselinux/include/selinux/get_default_type.h
@@ -0,0 +1,23 @@ +/* get_default_type.h - contains header information and function prototypes + * for functions to get the default type for a role + */ + +#ifndef _SELINUX_GET_DEFAULT_TYPE_H_ +#define _SELINUX_GET_DEFAULT_TYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return path to default type file. */ + const char *selinux_default_type_path(void); + +/* Get the default type (domain) for 'role' and set 'type' to refer to it. + Caller must free via free(). + Return 0 on success or -1 otherwise. */ + int get_default_type(const char *role, char **type); + +#ifdef __cplusplus +} +#endif +#endif /* ifndef _GET_DEFAULT_TYPE_H_ */
diff --git a/selinux/libselinux/include/selinux/label.h b/selinux/libselinux/include/selinux/label.h new file mode 100644 index 0000000..f0b1e10 --- /dev/null +++ b/selinux/libselinux/include/selinux/label.h
@@ -0,0 +1,188 @@ +/* + * Labeling interface for userspace object managers and others. + * + * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> + */ +#ifndef _SELABEL_H_ +#define _SELABEL_H_ + +#include <stdbool.h> +#include <sys/types.h> +#include <selinux/selinux.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Opaque type used for all label handles. + */ + +struct selabel_handle; + +/* + * Available backends. + */ + +/* file contexts */ +#define SELABEL_CTX_FILE 0 +/* media contexts */ +#define SELABEL_CTX_MEDIA 1 +/* x contexts */ +#define SELABEL_CTX_X 2 +/* db objects */ +#define SELABEL_CTX_DB 3 +/* Android property service contexts */ +#define SELABEL_CTX_ANDROID_PROP 4 + +/* + * Available options + */ + +/* no-op option, useful for unused slots in an array of options */ +#define SELABEL_OPT_UNUSED 0 +/* validate contexts before returning them (boolean value) */ +#define SELABEL_OPT_VALIDATE 1 +/* don't use local customizations to backend data (boolean value) */ +#define SELABEL_OPT_BASEONLY 2 +/* specify an alternate path to use when loading backend data */ +#define SELABEL_OPT_PATH 3 +/* select a subset of the search space as an optimization (file backend) */ +#define SELABEL_OPT_SUBSET 4 +/* require a hash calculation on spec files */ +#define SELABEL_OPT_DIGEST 5 +/* total number of options */ +#define SELABEL_NOPT 6 + +/* + * Label operations + */ + +/** + * selabel_open - Create a labeling handle. + * @backend: one of the constants specifying a supported labeling backend. + * @opts: array of selabel_opt structures specifying label options or NULL. + * @nopts: number of elements in opts array or zero for no options. + * + * Open a labeling backend for use. The available backend identifiers are + * listed above. Options may be provided via the opts parameter; available + * options are listed above. Not all options may be supported by every + * backend. Return value is the created handle on success or NULL with + * @errno set on failure. + */ +struct selabel_handle *selabel_open(unsigned int backend, + const struct selinux_opt *opts, + unsigned nopts); + +/** + * selabel_close - Close a labeling handle. + * @handle: specifies handle to close + * + * Destroy the specified handle, closing files, freeing allocated memory, + * etc. The handle may not be further used after it has been closed. + */ +void selabel_close(struct selabel_handle *handle); + +/** + * selabel_lookup - Perform labeling lookup operation. + * @handle: specifies backend instance to query + * @con: returns the appropriate context with which to label the object + * @key: string input to lookup operation + * @type: numeric input to the lookup operation + * + * Perform a labeling lookup operation. Return %0 on success, -%1 with + * @errno set on failure. The key and type arguments are the inputs to the + * lookup operation; appropriate values are dictated by the backend in use. + * The result is returned in the memory pointed to by @con and must be freed + * by the user with freecon(). + */ +int selabel_lookup(struct selabel_handle *handle, char **con, + const char *key, int type); +int selabel_lookup_raw(struct selabel_handle *handle, char **con, + const char *key, int type); + +bool selabel_partial_match(struct selabel_handle *handle, const char *key); + +int selabel_lookup_best_match(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type); +int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type); + +/** + * selabel_digest - Retrieve the SHA1 digest and the list of specfiles used to + * generate the digest. The SELABEL_OPT_DIGEST option must + * be set in selabel_open() to initiate the digest generation. + * @handle: specifies backend instance to query + * @digest: returns a pointer to the SHA1 digest. + * @digest_len: returns length of digest in bytes. + * @specfiles: a list of specfiles used in the SHA1 digest generation. + * The list is NULL terminated and will hold @num_specfiles entries. + * @num_specfiles: number of specfiles in the list. + * + * Return %0 on success, -%1 with @errno set on failure. + */ +int selabel_digest(struct selabel_handle *rec, + unsigned char **digest, size_t *digest_len, + char ***specfiles, size_t *num_specfiles); + +enum selabel_cmp_result { + SELABEL_SUBSET, + SELABEL_EQUAL, + SELABEL_SUPERSET, + SELABEL_INCOMPARABLE +}; + +/** + * selabel_cmp - Compare two label configurations. + * @h1: handle for the first label configuration + * @h2: handle for the first label configuration + * + * Compare two label configurations. + * Return %SELABEL_SUBSET if @h1 is a subset of @h2, %SELABEL_EQUAL + * if @h1 is identical to @h2, %SELABEL_SUPERSET if @h1 is a superset + * of @h2, and %SELABEL_INCOMPARABLE if @h1 and @h2 are incomparable. + */ +enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, + struct selabel_handle *h2); + +/** + * selabel_stats - log labeling operation statistics. + * @handle: specifies backend instance to query + * + * Log a message with information about the number of queries performed, + * number of unused matching entries, or other operational statistics. + * Message is backend-specific, some backends may not output a message. + */ +void selabel_stats(struct selabel_handle *handle); + +/* + * Type codes used by specific backends + */ + +/* X backend */ +#define SELABEL_X_PROP 1 +#define SELABEL_X_EXT 2 +#define SELABEL_X_CLIENT 3 +#define SELABEL_X_EVENT 4 +#define SELABEL_X_SELN 5 +#define SELABEL_X_POLYPROP 6 +#define SELABEL_X_POLYSELN 7 + +/* DB backend */ +#define SELABEL_DB_DATABASE 1 +#define SELABEL_DB_SCHEMA 2 +#define SELABEL_DB_TABLE 3 +#define SELABEL_DB_COLUMN 4 +#define SELABEL_DB_SEQUENCE 5 +#define SELABEL_DB_VIEW 6 +#define SELABEL_DB_PROCEDURE 7 +#define SELABEL_DB_BLOB 8 +#define SELABEL_DB_TUPLE 9 +#define SELABEL_DB_LANGUAGE 10 +#define SELABEL_DB_EXCEPTION 11 +#define SELABEL_DB_DATATYPE 12 + +#ifdef __cplusplus +} +#endif +#endif /* _SELABEL_H_ */
diff --git a/selinux/libselinux/include/selinux/restorecon.h b/selinux/libselinux/include/selinux/restorecon.h new file mode 100644 index 0000000..ba1232e --- /dev/null +++ b/selinux/libselinux/include/selinux/restorecon.h
@@ -0,0 +1,79 @@ +#ifndef _RESTORECON_H_ +#define _RESTORECON_H_ + +#include <sys/types.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * selinux_restorecon - Relabel files. + * @pathname: specifies file/directory to relabel. + * @restorecon_flags: specifies the actions to be performed when relabeling. + * + * selinux_restorecon(3) will automatically call + * selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3) + * first time through to set the selabel_open(3) parameters to use the + * currently loaded policy file_contexts and request their computed digest. + * + * Should other selabel_open(3) parameters be required see + * selinux_restorecon_set_sehandle(3). + */ +extern int selinux_restorecon(const char *pathname, + unsigned int restorecon_flags); +/* + * restorecon_flags options + */ +/* Force the checking of labels even if the stored SHA1 + * digest matches the specfiles SHA1 digest. */ +#define SELINUX_RESTORECON_IGNORE_DIGEST 1 +/* Do not change file labels */ +#define SELINUX_RESTORECON_NOCHANGE 2 +/* If set set change file label to that in spec file. + * If not only change type component to that in spec file. */ +#define SELINUX_RESTORECON_SET_SPECFILE_CTX 4 +/* Recursively descend directories */ +#define SELINUX_RESTORECON_RECURSE 8 +/* Log changes to selinux log. Note that if VERBOSE and + * PROGRESS are set, then PROGRESS will take precedence. */ +#define SELINUX_RESTORECON_VERBOSE 16 +/* Show progress by printing * to stdout every 1000 files */ +#define SELINUX_RESTORECON_PROGRESS 32 +/* Convert passed-in pathname to canonical pathname */ +#define SELINUX_RESTORECON_REALPATH 64 +/* Prevent descending into directories that have a different + * device number than the pathname from which the descent began */ +#define SELINUX_RESTORECON_XDEV 128 + +/** + * selinux_restorecon_set_sehandle - Set the global fc handle. + * @handle: specifies handle to set as the global fc handle. + * + * Called by a process that has already called selabel_open(3) with it's + * required parameters, or if selinux_restorecon_default_handle(3) has been + * called to set the default selabel_open(3) parameters. + */ +extern void selinux_restorecon_set_sehandle(struct selabel_handle *hndl); + +/** + * selinux_restorecon_default_handle - Sets default selabel_open(3) parameters + * to use the currently loaded policy and + * file_contexts, also requests the digest. + */ +extern struct selabel_handle *selinux_restorecon_default_handle(void); + +/** + * selinux_restorecon_set_exclude_list - Add a list of files or + * directories that are to be excluded + * from relabeling. + * @exclude_list: containing a NULL terminated list of one or more + * directories or files not to be relabeled. + */ +extern void selinux_restorecon_set_exclude_list(const char **exclude_list); + +#ifdef __cplusplus +} +#endif +#endif
diff --git a/selinux/libselinux/include/selinux/selinux.h b/selinux/libselinux/include/selinux/selinux.h new file mode 100644 index 0000000..2262086 --- /dev/null +++ b/selinux/libselinux/include/selinux/selinux.h
@@ -0,0 +1,671 @@ +#ifndef _SELINUX_H_ +#define _SELINUX_H_ + +#include <sys/types.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */ +extern int is_selinux_enabled(void); +/* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */ +extern int is_selinux_mls_enabled(void); + +/* No longer used; here for compatibility with legacy callers. */ +typedef char *security_context_t; + +/* Free the memory allocated for a context by any of the below get* calls. */ +extern void freecon(char * con); + +/* Free the memory allocated for a context array by security_compute_user. */ +extern void freeconary(char ** con); + +/* Wrappers for the /proc/pid/attr API. */ + +/* Get current context, and set *con to refer to it. + Caller must free via freecon. */ +extern int getcon(char ** con); +extern int getcon_raw(char ** con); + +/* Set the current security context to con. + Note that use of this function requires that the entire application + be trusted to maintain any desired separation between the old and new + security contexts, unlike exec-based transitions performed via setexeccon. + When possible, decompose your application and use setexeccon()+execve() + instead. Note that the application may lose access to its open descriptors + as a result of a setcon() unless policy allows it to use descriptors opened + by the old context. */ +extern int setcon(const char * con); +extern int setcon_raw(const char * con); + +/* Get context of process identified by pid, and + set *con to refer to it. Caller must free via freecon. */ +extern int getpidcon(pid_t pid, char ** con); +extern int getpidcon_raw(pid_t pid, char ** con); + +/* Get previous context (prior to last exec), and set *con to refer to it. + Caller must free via freecon. */ +extern int getprevcon(char ** con); +extern int getprevcon_raw(char ** con); + +/* Get exec context, and set *con to refer to it. + Sets *con to NULL if no exec context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getexeccon(char ** con); +extern int getexeccon_raw(char ** con); + +/* Set exec security context for the next execve. + Call with NULL if you want to reset to the default. */ +extern int setexeccon(const char * con); +extern int setexeccon_raw(const char * con); + +/* Get fscreate context, and set *con to refer to it. + Sets *con to NULL if no fs create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getfscreatecon(char ** con); +extern int getfscreatecon_raw(char ** con); + +/* Set the fscreate security context for subsequent file creations. + Call with NULL if you want to reset to the default. */ +extern int setfscreatecon(const char * context); +extern int setfscreatecon_raw(const char * context); + +/* Get keycreate context, and set *con to refer to it. + Sets *con to NULL if no key create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getkeycreatecon(char ** con); +extern int getkeycreatecon_raw(char ** con); + +/* Set the keycreate security context for subsequent key creations. + Call with NULL if you want to reset to the default. */ +extern int setkeycreatecon(const char * context); +extern int setkeycreatecon_raw(const char * context); + +/* Get sockcreate context, and set *con to refer to it. + Sets *con to NULL if no socket create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getsockcreatecon(char ** con); +extern int getsockcreatecon_raw(char ** con); + +/* Set the sockcreate security context for subsequent socket creations. + Call with NULL if you want to reset to the default. */ +extern int setsockcreatecon(const char * context); +extern int setsockcreatecon_raw(const char * context); + +/* Wrappers for the xattr API. */ + +/* Get file context, and set *con to refer to it. + Caller must free via freecon. */ +extern int getfilecon(const char *path, char ** con); +extern int getfilecon_raw(const char *path, char ** con); +extern int lgetfilecon(const char *path, char ** con); +extern int lgetfilecon_raw(const char *path, char ** con); +extern int fgetfilecon(int fd, char ** con); +extern int fgetfilecon_raw(int fd, char ** con); + +/* Set file context */ +extern int setfilecon(const char *path, const char * con); +extern int setfilecon_raw(const char *path, const char * con); +extern int lsetfilecon(const char *path, const char * con); +extern int lsetfilecon_raw(const char *path, const char * con); +extern int fsetfilecon(int fd, const char * con); +extern int fsetfilecon_raw(int fd, const char * con); + +/* Wrappers for the socket API */ + +/* Get context of peer socket, and set *con to refer to it. + Caller must free via freecon. */ +extern int getpeercon(int fd, char ** con); +extern int getpeercon_raw(int fd, char ** con); + +/* Wrappers for the selinuxfs (policy) API. */ + +typedef unsigned int access_vector_t; +typedef unsigned short security_class_t; + +struct av_decision { + access_vector_t allowed; + access_vector_t decided; + access_vector_t auditallow; + access_vector_t auditdeny; + unsigned int seqno; + unsigned int flags; +}; + +/* Definitions of av_decision.flags */ +#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 + +/* Structure for passing options, used by AVC and label subsystems */ +struct selinux_opt { + int type; + const char *value; +}; + +/* Callback facilities */ +union selinux_callback { + /* log the printf-style format and arguments, + with the type code indicating the type of message */ + int +#ifdef __GNUC__ +__attribute__ ((format(printf, 2, 3))) +#endif + (*func_log) (int type, const char *fmt, ...); + /* store a string representation of auditdata (corresponding + to the given security class) into msgbuf. */ + int (*func_audit) (void *auditdata, security_class_t cls, + char *msgbuf, size_t msgbufsize); + /* validate the supplied context, modifying if necessary */ + int (*func_validate) (char **ctx); + /* netlink callback for setenforce message */ + int (*func_setenforce) (int enforcing); + /* netlink callback for policyload message */ + int (*func_policyload) (int seqno); +}; + +#define SELINUX_CB_LOG 0 +#define SELINUX_CB_AUDIT 1 +#define SELINUX_CB_VALIDATE 2 +#define SELINUX_CB_SETENFORCE 3 +#define SELINUX_CB_POLICYLOAD 4 + +extern union selinux_callback selinux_get_callback(int type); +extern void selinux_set_callback(int type, union selinux_callback cb); + + /* Logging type codes, passed to the logging callback */ +#define SELINUX_ERROR 0 +#define SELINUX_WARNING 1 +#define SELINUX_INFO 2 +#define SELINUX_AVC 3 +#define SELINUX_TRANS_DIR "/var/run/setrans" + +/* Compute an access decision. */ +extern int security_compute_av(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); +extern int security_compute_av_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); + +extern int security_compute_av_flags(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); +extern int security_compute_av_flags_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); + +/* Compute a labeling decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_create(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_create_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_create_name(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon); +extern int security_compute_create_name_raw(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon); + +/* Compute a relabeling decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_relabel(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_relabel_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); + +/* Compute a polyinstantiation member decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_member(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_member_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); + +/* Compute the set of reachable user contexts and set *con to refer to + the NULL-terminated array of contexts. Caller must free via freeconary. */ +extern int security_compute_user(const char * scon, + const char *username, + char *** con); +extern int security_compute_user_raw(const char * scon, + const char *username, + char *** con); + +/* Load a policy configuration. */ +extern int security_load_policy(void *data, size_t len); + +/* Get the context of an initial kernel security identifier by name. + Caller must free via freecon */ +extern int security_get_initial_context(const char *name, + char ** con); +extern int security_get_initial_context_raw(const char *name, + char ** con); + +/* + * Make a policy image and load it. + * This function provides a higher level interface for loading policy + * than security_load_policy, internally determining the right policy + * version, locating and opening the policy file, mapping it into memory, + * manipulating it as needed for current boolean settings and/or local + * definitions, and then calling security_load_policy to load it. + * + * 'preservebools' is a boolean flag indicating whether current + * policy boolean values should be preserved into the new policy (if 1) + * or reset to the saved policy settings (if 0). The former case is the + * default for policy reloads, while the latter case is an option for policy + * reloads but is primarily for the initial policy load. + */ +extern int selinux_mkload_policy(int preservebools); + +/* + * Perform the initial policy load. + * This function determines the desired enforcing mode, sets the + * the *enforce argument accordingly for the caller to use, sets the + * SELinux kernel enforcing status to match it, and loads the policy. + * It also internally handles the initial selinuxfs mount required to + * perform these actions. + * + * The function returns 0 if everything including the policy load succeeds. + * In this case, init is expected to re-exec itself in order to transition + * to the proper security context. + * Otherwise, the function returns -1, and init must check *enforce to + * determine how to proceed. If enforcing (*enforce > 0), then init should + * halt the system. Otherwise, init may proceed normally without a re-exec. + */ +extern int selinux_init_load_policy(int *enforce); + +/* Translate boolean strict to name value pair. */ +typedef struct { + char *name; + int value; +} SELboolean; +/* save a list of booleans in a single transaction. */ +extern int security_set_boolean_list(size_t boolcnt, + SELboolean * boollist, int permanent); + +/* Load policy boolean settings. + Path may be NULL, in which case the booleans are loaded from + the active policy boolean configuration file. */ +extern int security_load_booleans(char *path); + +/* Check the validity of a security context. */ +extern int security_check_context(const char * con); +extern int security_check_context_raw(const char * con); + +/* Canonicalize a security context. */ +extern int security_canonicalize_context(const char * con, + char ** canoncon); +extern int security_canonicalize_context_raw(const char * con, + char ** canoncon); + +/* Get the enforce flag value. */ +extern int security_getenforce(void); + +/* Set the enforce flag value. */ +extern int security_setenforce(int value); + +/* Get the behavior for undefined classes/permissions */ +extern int security_deny_unknown(void); + +/* Disable SELinux at runtime (must be done prior to initial policy load). */ +extern int security_disable(void); + +/* Get the policy version number. */ +extern int security_policyvers(void); + +/* Get the boolean names */ +extern int security_get_boolean_names(char ***names, int *len); + +/* Get the pending value for the boolean */ +extern int security_get_boolean_pending(const char *name); + +/* Get the active value for the boolean */ +extern int security_get_boolean_active(const char *name); + +/* Set the pending value for the boolean */ +extern int security_set_boolean(const char *name, int value); + +/* Commit the pending values for the booleans */ +extern int security_commit_booleans(void); + +/* Userspace class mapping support */ +struct security_class_mapping { + const char *name; + const char *perms[sizeof(access_vector_t) * 8 + 1]; +}; + +/** + * selinux_set_mapping - Enable dynamic mapping between integer offsets and security class names + * @map: array of security_class_mapping structures + * + * The core avc_has_perm() API uses integers to represent security + * classes; previous to the introduction of this function, it was + * common for userspace object managers to be compiled using generated + * offsets for a particular policy. However, that strongly ties the build of the userspace components to a particular policy. + * + * By using this function to map between integer offsets and security + * class names, it's possible to replace a system policies that have + * at least the same set of security class names as used by the + * userspace object managers. + * + * To correctly use this function, you should override the generated + * security class defines from the system policy in a local header, + * starting at 1, and have one security_class_mapping structure entry + * per define. + */ +extern int selinux_set_mapping(struct security_class_mapping *map); + +/* Common helpers */ + +/* Convert between mode and security class values */ +extern security_class_t mode_to_security_class(mode_t mode); +/* Convert between security class values and string names */ +extern security_class_t string_to_security_class(const char *name); +extern const char *security_class_to_string(security_class_t cls); + +/* Convert between individual access vector permissions and string names */ +extern const char *security_av_perm_to_string(security_class_t tclass, + access_vector_t perm); +extern access_vector_t string_to_av_perm(security_class_t tclass, + const char *name); + +/* Returns an access vector in a string representation. User must free the + * returned string via free(). */ +extern int security_av_string(security_class_t tclass, + access_vector_t av, char **result); + +/* Display an access vector in a string representation. */ +extern void print_access_vector(security_class_t tclass, access_vector_t av); + +/* Set the function used by matchpathcon_init when displaying + errors about the file_contexts configuration. If not set, + then this defaults to fprintf(stderr, fmt, ...). */ +extern void set_matchpathcon_printf(void (*f) (const char *fmt, ...)); + +/* Set the function used by matchpathcon_init when checking the + validity of a context in the file contexts configuration. If not set, + then this defaults to a test based on security_check_context(). + The function is also responsible for reporting any such error, and + may include the 'path' and 'lineno' in such error messages. */ +extern void set_matchpathcon_invalidcon(int (*f) (const char *path, + unsigned lineno, + char *context)); + +/* Same as above, but also allows canonicalization of the context, + by changing *context to refer to the canonical form. If not set, + and invalidcon is also not set, then this defaults to calling + security_canonicalize_context(). */ +extern void set_matchpathcon_canoncon(int (*f) (const char *path, + unsigned lineno, + char **context)); + +/* Set flags controlling operation of matchpathcon_init or matchpathcon. */ +#define MATCHPATHCON_BASEONLY 1 /* Only process the base file_contexts file. */ +#define MATCHPATHCON_NOTRANS 2 /* Do not perform any context translation. */ +#define MATCHPATHCON_VALIDATE 4 /* Validate/canonicalize contexts at init time. */ +extern void set_matchpathcon_flags(unsigned int flags); + +/* Load the file contexts configuration specified by 'path' + into memory for use by subsequent matchpathcon calls. + If 'path' is NULL, then load the active file contexts configuration, + i.e. the path returned by selinux_file_context_path(). + Unless the MATCHPATHCON_BASEONLY flag has been set, this + function also checks for a 'path'.homedirs file and + a 'path'.local file and loads additional specifications + from them if present. */ +extern int matchpathcon_init(const char *path); + +/* Same as matchpathcon_init, but only load entries with + regexes that have stems that are prefixes of 'prefix'. */ +extern int matchpathcon_init_prefix(const char *path, const char *prefix); + +/* Free the memory allocated by matchpathcon_init. */ +extern void matchpathcon_fini(void); + +/* Resolve all of the symlinks and relative portions of a pathname, but NOT + * the final component (same a realpath() unless the final component is a + * symlink. Resolved path must be a path of size PATH_MAX + 1 */ +extern int realpath_not_final(const char *name, char *resolved_path); + +/* Match the specified pathname and mode against the file contexts + configuration and set *con to refer to the resulting context. + 'mode' can be 0 to disable mode matching. + Caller must free via freecon. + If matchpathcon_init has not already been called, then this function + will call it upon its first invocation with a NULL path. */ +extern int matchpathcon(const char *path, + mode_t mode, char ** con); + +/* Same as above, but return a specification index for + later use in a matchpathcon_filespec_add() call - see below. */ +extern int matchpathcon_index(const char *path, + mode_t mode, char ** con); + +/* Maintain an association between an inode and a specification index, + and check whether a conflicting specification is already associated + with the same inode (e.g. due to multiple hard links). If so, then + use the latter of the two specifications based on their order in the + file contexts configuration. Return the used specification index. */ +extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file); + +/* Destroy any inode associations that have been added, e.g. to restart + for a new filesystem. */ +extern void matchpathcon_filespec_destroy(void); + +/* Display statistics on the hash table usage for the associations. */ +extern void matchpathcon_filespec_eval(void); + +/* Check to see whether any specifications had no matches and report them. + The 'str' is used as a prefix for any warning messages. */ +extern void matchpathcon_checkmatches(char *str); + +/* Match the specified media and against the media contexts + configuration and set *con to refer to the resulting context. + Caller must free con via freecon. */ +extern int matchmediacon(const char *media, char ** con); + +/* + selinux_getenforcemode reads the /etc/selinux/config file and determines + whether the machine should be started in enforcing (1), permissive (0) or + disabled (-1) mode. + */ +extern int selinux_getenforcemode(int *enforce); + +/* + selinux_boolean_sub reads the /etc/selinux/TYPE/booleans.subs_dist file + looking for a record with boolean_name. If a record exists selinux_boolean_sub + returns the translated name otherwise it returns the original name. + The returned value needs to be freed. On failure NULL will be returned. + */ +extern char *selinux_boolean_sub(const char *boolean_name); + +/* + selinux_getpolicytype reads the /etc/selinux/config file and determines + what the default policy for the machine is. Calling application must + free policytype. + */ +extern int selinux_getpolicytype(char **policytype); + +/* + selinux_policy_root reads the /etc/selinux/config file and returns + the directory path under which the compiled policy file and context + configuration files exist. + */ +extern const char *selinux_policy_root(void); + +/* + selinux_set_policy_root sets an alternate policy root directory path under + which the compiled policy file and context configuration files exist. + */ +extern int selinux_set_policy_root(const char *rootpath); + +/* These functions return the paths to specific files under the + policy root directory. */ +extern const char *selinux_current_policy_path(void); +extern const char *selinux_binary_policy_path(void); +extern const char *selinux_failsafe_context_path(void); +extern const char *selinux_removable_context_path(void); +extern const char *selinux_default_context_path(void); +extern const char *selinux_user_contexts_path(void); +extern const char *selinux_file_context_path(void); +extern const char *selinux_file_context_homedir_path(void); +extern const char *selinux_file_context_local_path(void); +extern const char *selinux_file_context_subs_path(void); +extern const char *selinux_file_context_subs_dist_path(void); +extern const char *selinux_homedir_context_path(void); +extern const char *selinux_media_context_path(void); +extern const char *selinux_virtual_domain_context_path(void); +extern const char *selinux_virtual_image_context_path(void); +extern const char *selinux_lxc_contexts_path(void); +extern const char *selinux_x_context_path(void); +extern const char *selinux_sepgsql_context_path(void); +extern const char *selinux_openssh_contexts_path(void); +extern const char *selinux_systemd_contexts_path(void); +extern const char *selinux_contexts_path(void); +extern const char *selinux_securetty_types_path(void); +extern const char *selinux_booleans_subs_path(void); +extern const char *selinux_booleans_path(void); +extern const char *selinux_customizable_types_path(void); +extern const char *selinux_users_path(void); +extern const char *selinux_usersconf_path(void); +extern const char *selinux_translations_path(void); +extern const char *selinux_colors_path(void); +extern const char *selinux_netfilter_context_path(void); +extern const char *selinux_path(void); + +/** + * selinux_check_access - Check permissions and perform appropriate auditing. + * @scon: source security context + * @tcon: target security context + * @tclass: target security class string + * @perm: requested permissions string, interpreted based on @tclass + * @auditdata: auxiliary audit data + * + * Check the AVC to determine whether the @perm permissions are granted + * for the SID pair (@scon, @tcon), interpreting the permissions + * based on @tclass. + * Return %0 if all @perm permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied or to another + * value upon other errors. + * If auditing or logging is configured the appropriate callbacks will be called + * and passed the auditdata field + */ +extern int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata); + +/* Check a permission in the passwd class. + Return 0 if granted or -1 otherwise. */ +extern int selinux_check_passwd_access(access_vector_t requested); +extern int checkPasswdAccess(access_vector_t requested); + +/* Check if the tty_context is defined as a securetty + Return 0 if secure, < 0 otherwise. */ +extern int selinux_check_securetty_context(const char * tty_context); + +/* Set the path to the selinuxfs mount point explicitly. + Normally, this is determined automatically during libselinux + initialization, but this is not always possible, e.g. for /sbin/init + which performs the initial mount of selinuxfs. */ +void set_selinuxmnt(const char *mnt); + +/* Check if selinuxfs exists as a kernel filesystem */ +int selinuxfs_exists(void); + +/* clear selinuxmnt variable and free allocated memory */ +void fini_selinuxmnt(void); + +/* Set an appropriate security context based on the filename of a helper + * program, falling back to a new context with the specified type. */ +extern int setexecfilecon(const char *filename, const char *fallback_type); + +#ifndef DISABLE_RPM +/* Execute a helper for rpm in an appropriate security context. */ +extern int rpm_execcon(unsigned int verified, + const char *filename, + char *const argv[], char *const envp[]); +#endif + +/* Returns whether a file context is customizable, and should not + be relabeled . */ +extern int is_context_customizable(const char * scontext); + +/* Perform context translation between the human-readable format + ("translated") and the internal system format ("raw"). + Caller must free the resulting context via freecon. + Returns -1 upon an error or 0 otherwise. + If passed NULL, sets the returned context to NULL and returns 0. */ +extern int selinux_trans_to_raw_context(const char * trans, + char ** rawp); +extern int selinux_raw_to_trans_context(const char * raw, + char ** transp); + +/* Perform context translation between security contexts + and display colors. Returns a space-separated list of ten + ten hex RGB triples prefixed by hash marks, e.g. "#ff0000". + Caller must free the resulting string via free. + Returns -1 upon an error or 0 otherwise. */ +extern int selinux_raw_context_to_color(const char * raw, + char **color_str); + +/* Get the SELinux username and level to use for a given Linux username. + These values may then be passed into the get_ordered_context_list* + and get_default_context* functions to obtain a context for the user. + Returns 0 on success or -1 otherwise. + Caller must free the returned strings via free. */ +extern int getseuserbyname(const char *linuxuser, char **seuser, char **level); + +/* Get the SELinux username and level to use for a given Linux username and service. + These values may then be passed into the get_ordered_context_list* + and get_default_context* functions to obtain a context for the user. + Returns 0 on success or -1 otherwise. + Caller must free the returned strings via free. */ +extern int getseuser(const char *username, const char *service, + char **r_seuser, char **r_level); + +/* Compare two file contexts, return 0 if equivalent. */ +extern int selinux_file_context_cmp(const char * a, + const char * b); + +/* + * Verify the context of the file 'path' against policy. + * Return 1 if match, 0 if not and -1 on error. + */ +extern int selinux_file_context_verify(const char *path, mode_t mode); + +/* This function sets the file context on to the system defaults returns 0 on success */ +extern int selinux_lsetfilecon_default(const char *path); + +/* + * Force a reset of the loaded configuration + * WARNING: This is not thread safe. Be very sure that no other threads + * are calling into libselinux when this is called. + */ +extern void selinux_reset_config(void); + +#ifdef __cplusplus +} +#endif +#endif
diff --git a/selinux/libselinux/man/Makefile b/selinux/libselinux/man/Makefile new file mode 100644 index 0000000..0643e6a --- /dev/null +++ b/selinux/libselinux/man/Makefile
@@ -0,0 +1,18 @@ +# Installation directories. +MAN8DIR ?= $(DESTDIR)/usr/share/man/man8 +MAN5DIR ?= $(DESTDIR)/usr/share/man/man5 +MAN3DIR ?= $(DESTDIR)/usr/share/man/man3 + +all: + +install: all + mkdir -p $(MAN3DIR) + mkdir -p $(MAN5DIR) + mkdir -p $(MAN8DIR) + install -m 644 man3/*.3 $(MAN3DIR) + install -m 644 man5/*.5 $(MAN5DIR) + install -m 644 man8/*.8 $(MAN8DIR) + +relabel: + +indent distclean clean:
diff --git a/selinux/libselinux/man/man3/avc_add_callback.3 b/selinux/libselinux/man/man3/avc_add_callback.3 new file mode 100644 index 0000000..bdbbadf --- /dev/null +++ b/selinux/libselinux/man/man3/avc_add_callback.3
@@ -0,0 +1,192 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_add_callback" "3" "9 June 2004" "" "SELinux API documentation" +.SH "NAME" +avc_add_callback \- additional event notification for SELinux userspace object managers +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_add_callback(int (*" callback ")(uint32_t " event , +.in +\w'int avc_add_callback(int (*callback)('u +.BI "security_id_t " ssid , +.br +.BI "security_id_t " tsid , +.br +.BI "security_class_t " tclass , +.br +.BI "access_vector_t " perms , +.br +.BI "access_vector_t *" out_retained ")," +.in +.in +\w'int avc_add_callback('u +.BI "uint32_t " events ", security_id_t " ssid , +.br +.BI "security_id_t " tsid ", security_class_t " tclass , +.br +.BI "access_vector_t " perms ");" +.in +. +.SH "DESCRIPTION" +.BR avc_add_callback () +is used to register callback functions on security events. The purpose of this functionality is to allow userspace object managers to take additional action when a policy change, usually a policy reload, causes permissions to be granted or revoked. + +.I events +is the +.RI bitwise- or +of security events on which to register the callback; see +.B SECURITY EVENTS +below. + +.IR ssid , +.IR tsid , +.IR tclass , +and +.I perms +specify the source and target SID's, target class, and specific permissions that the callback wishes to monitor. The special symbol +.B SECSID_WILD +may be passed as the +.I source +or +.I target +and will cause any SID to match. + +.I callback +is the callback function provided by the userspace object manager. The +.I event +argument indicates the security event which occurred; the remaining arguments +are interpreted according to the event as described below. The return value +of the callback should be zero on success, \-1 on error with +.I errno +set appropriately (but see +.B RETURN VALUE +below). +. +.SH "SECURITY EVENTS" +In all cases below, +.I ssid +and/or +.I tsid +may be set to +.BR SECSID_WILD , +indicating that the change applies to all source and/or target SID's. Unless otherwise indicated, the +.I out_retained +parameter is unused. +. +.TP +.B AVC_CALLBACK_GRANT +Previously denied permissions are now granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to grant. +.TP +.B AVC_CALLBACK_TRY_REVOKE +Previously granted permissions are now conditionally revoked for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to revoke. The callback should set +.I out_retained +to the subset of +.I perms +which are retained as migrated permissions. Note that +.I out_retained +is ignored if the callback returns \-1. +.TP +.B AVC_CALLBACK_REVOKE +Previously granted permissions are now unconditionally revoked for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to revoke. +.TP +.B AVC_CALLBACK_RESET +Indicates that the cache was flushed. The SID, class, and permission arguments are unused and are set to NULL. +.TP +.B AVC_CALLBACK_AUDITALLOW_ENABLE +The permissions given by +.I perms +should now be audited when granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITALLOW_DISABLE +The permissions given by +.I perms +should no longer be audited when granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITDENY_ENABLE +The permissions given by +.I perms +should now be audited when denied for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITDENY_DISABLE +The permissions given by +.I perms +should no longer be audited when denied for +.IR ssid , +.I tsid +with respect to +.IR tclass . +. +.SH "RETURN VALUE" +On success, +.BR avc_add_callback () +returns zero. On error, \-1 is returned and +.I errno +is set appropriately. + +A return value of \-1 from a callback is interpreted as a failed policy operation. If such a return value is encountered, all remaining callbacks registered on the event are called. In threaded mode, the netlink handler thread may then terminate and cause the userspace AVC to return +.B EINVAL +on all further permission checks until +.BR avc_destroy (3) +is called. In non-threaded mode, the permission check on which the error occurred will return \-1 and the value of +.I errno +encountered to the caller. In both cases, a log message is produced and the kernel may be notified of the error. +. +.SH "ERRORS" +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "NOTES" +If the userspace AVC is running in threaded mode, callbacks registered via +.BR avc_add_callback () +may be executed in the context of the netlink handler thread. This will likely introduce synchronization issues requiring the use of locks. See +.BR avc_init (3). + +Support for dynamic revocation and retained permissions is mostly unimplemented in the SELinux kernel module. The only security event that currently gets exercised is +.BR AVC_CALLBACK_RESET . +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR security_compute_av (3) +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_audit.3 b/selinux/libselinux/man/man3/avc_audit.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/selinux/libselinux/man/man3/avc_audit.3
@@ -0,0 +1 @@ +.so man3/avc_has_perm.3
diff --git a/selinux/libselinux/man/man3/avc_av_stats.3 b/selinux/libselinux/man/man3/avc_av_stats.3 new file mode 100644 index 0000000..6732dc1 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_av_stats.3
@@ -0,0 +1 @@ +.so man3/avc_cache_stats.3
diff --git a/selinux/libselinux/man/man3/avc_cache_stats.3 b/selinux/libselinux/man/man3/avc_cache_stats.3 new file mode 100644 index 0000000..c00f090 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_cache_stats.3
@@ -0,0 +1,103 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_cache_stats" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_cache_stats, avc_av_stats, avc_sid_stats \- obtain userspace SELinux AVC statistics +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "void avc_av_stats(void);" +.sp +.BI "void avc_sid_stats(void);" +.sp +.BI "void avc_cache_stats(struct avc_cache_stats *" stats ");" +. +.SH "DESCRIPTION" +The userspace AVC maintains two internal hash tables, one to store security ID's and one to cache access decisions. + +.BR avc_av_stats () +and +.BR avc_sid_stats () +produce log messages indicating the status of the access decision and SID tables, respectively. The messages contain the number of entries in the table, number of hash buckets and number of buckets used, and maximum number of entries in a single bucket. + +.BR avc_cache_stats () +populates a structure whose fields reflect cache activity: + +.RS +.ta 4n 14n +.nf +struct avc_cache_stats { + unsigned entry_lookups; + unsigned entry_hits; + unsigned entry_misses; + unsigned entry_discards; + unsigned cav_lookups; + unsigned cav_hits; + unsigned cav_probes; + unsigned cav_misses; +}; +.fi +.ta +.RE + +.TP +.I entry_lookups +Number of queries made. +.TP +.I entry_hits +Number of times a decision was found in the +.I aeref +argument. +.TP +.I entry_misses +Number of times a decision was not found in the +.I aeref +argument. +.TP +.I entry_discards +Number of times a decision was not found in the +.I aeref +argument and the +.I aeref +argument was non-NULL. +.TP +.I cav_lookups +Number of cache lookups. +.TP +.I cav_hits +Number of cache hits. +.TP +.I cav_misses +Number of cache misses. +.TP +.I cav_probes +Number of entries examined while searching the cache. +. +.SH "NOTES" +When the cache is flushed as a result of a call to +.BR avc_reset () +or a policy change notification, +the statistics returned by +.BR avc_cache_stats () +are reset to zero. The SID table, however, is left +unchanged. + +When a policy change notification is received, a call to +.BR avc_av_stats () +is made before the cache is flushed. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_add_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_cleanup.3 b/selinux/libselinux/man/man3/avc_cleanup.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/selinux/libselinux/man/man3/avc_cleanup.3
@@ -0,0 +1 @@ +.so man3/avc_open.3
diff --git a/selinux/libselinux/man/man3/avc_compute_create.3 b/selinux/libselinux/man/man3/avc_compute_create.3 new file mode 100644 index 0000000..ce615bf --- /dev/null +++ b/selinux/libselinux/man/man3/avc_compute_create.3
@@ -0,0 +1,64 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "avc_compute_create" "3" "30 Mar 2007" "" "SELinux API documentation" +.SH "NAME" +avc_compute_create, avc_compute_member \- obtain SELinux label for new object +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_compute_create(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_compute_create('u +.BI "security_class_t " tclass ", security_id_t *" newsid ");" +.sp +.in +.BI "int avc_compute_member(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_compute_member('u +.BI "security_class_t " tclass ", security_id_t *" newsid ");" +.in +. +.SH "DESCRIPTION" +.BR avc_compute_create () +is used to compute a SID to use for labeling a new object in a particular class based on a SID pair. This call is identical to +.BR security_compute_create (), +but does not require converting from userspace SID's to contexts and back again. + +.BR avc_compute_member () +is used to compute a SID to use for labeling a polyinstantiated object instance of a particular class based on a SID pair. This call is identical to +.BR security_compute_member (), +but does not require converting from userspace SID's to contexts and back again. + +These functions +return a SID for the computed context in the memory referenced by +.IR sid . +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +The +.I tclass +and/or the security contexts referenced by +.I ssid +and +.I tsid +are not recognized by the currently loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR avc_init (3), +.BR avc_context_to_sid (3), +.BR security_compute_create (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_compute_member.3 b/selinux/libselinux/man/man3/avc_compute_member.3 new file mode 100644 index 0000000..28307ce --- /dev/null +++ b/selinux/libselinux/man/man3/avc_compute_member.3
@@ -0,0 +1 @@ +.so man3/avc_compute_create.3
diff --git a/selinux/libselinux/man/man3/avc_context_to_sid.3 b/selinux/libselinux/man/man3/avc_context_to_sid.3 new file mode 100644 index 0000000..021ff37 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_context_to_sid.3
@@ -0,0 +1,73 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_context_to_sid" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_context_to_sid, avc_sid_to_context, avc_get_initial_sid \- obtain and manipulate SELinux security ID's +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_context_to_sid(char * " ctx ", security_id_t *" sid ");" +.sp +.BI "int avc_sid_to_context(security_id_t " sid ", char **" ctx ");" +.sp +.BI "int avc_get_initial_sid(const char *" name ", security_id_t *" sid ");" +. +.SH "DESCRIPTION" +Security ID's (SID's) are opaque representations of security contexts, managed by the userspace AVC. + +.BR avc_context_to_sid () +returns a SID for the given +.I context +in the memory referenced by +.IR sid . + +.BR avc_sid_to_context () +returns a copy of the context represented by +.I sid +in the memory referenced by +.IR ctx . +The user must free the copy with +.BR freecon (3). + +.BR avc_get_initial_sid () +returns a SID for the kernel initial security identifier specified by +.IR name . +. +.SH "RETURN VALUE" +.BR avc_context_to_sid () +and +.BR avc_sid_to_context () +return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOMEM +An attempt to allocate memory failed. +.SH "NOTES" +As of libselinux version 2.0.86, SID's are no longer reference counted. A SID will be valid from the time it is first obtained until the next call to +.BR avc_destroy (3). +The +.BR sidget (3) +and +.BR sidput (3) +functions, formerly used to adjust the reference count, are no-ops and are deprecated. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR getcon (3), +.BR freecon (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_destroy.3 b/selinux/libselinux/man/man3/avc_destroy.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/selinux/libselinux/man/man3/avc_destroy.3
@@ -0,0 +1 @@ +.so man3/avc_open.3
diff --git a/selinux/libselinux/man/man3/avc_entry_ref_init.3 b/selinux/libselinux/man/man3/avc_entry_ref_init.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/selinux/libselinux/man/man3/avc_entry_ref_init.3
@@ -0,0 +1 @@ +.so man3/avc_has_perm.3
diff --git a/selinux/libselinux/man/man3/avc_get_initial_context.3 b/selinux/libselinux/man/man3/avc_get_initial_context.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_get_initial_context.3
@@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3
diff --git a/selinux/libselinux/man/man3/avc_get_initial_sid.3 b/selinux/libselinux/man/man3/avc_get_initial_sid.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_get_initial_sid.3
@@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3
diff --git a/selinux/libselinux/man/man3/avc_has_perm.3 b/selinux/libselinux/man/man3/avc_has_perm.3 new file mode 100644 index 0000000..3e9fca8 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_has_perm.3
@@ -0,0 +1,159 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_has_perm" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_has_perm, avc_has_perm_noaudit, avc_audit, avc_entry_ref_init \- obtain and audit SELinux access decisions +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "void avc_entry_ref_init(struct avc_entry_ref *" aeref ");" +.sp +.BI "int avc_has_perm(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_has_perm('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct avc_entry_ref *" aeref ", void *" auditdata ");" +.in +.sp +.BI "int avc_has_perm_noaudit(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_has_perm('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct avc_entry_ref *" aeref ", struct av_decision *" avd ");" +.in +.sp +.BI "void avc_audit(security_id_t " ssid ", security_id_t " tsid , +.in +\w'void avc_audit('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct av_decision *" avd ", int " result ", void *" auditdata ");" +.in +. +.SH "DESCRIPTION" +.BR avc_entry_ref_init () +initializes an +.B avc_entry_ref +structure; see +.B ENTRY REFERENCES +below. This function may be implemented as a macro. + +.BR avc_has_perm () +checks whether the +.I requested +permissions are granted +for subject SID +.IR ssid +and target SID +.IR tsid , +interpreting the permissions +based on +.I tclass +and updating +.IR aeref , +if non-NULL, to refer to a cache entry with the resulting decision. The granting or denial of permissions is audited in accordance with the policy. The +.I auditdata +parameter is for supplemental auditing; see +.BR avc_audit () +below. + +.BR avc_has_perm_noaudit () +behaves as +.BR avc_has_perm () +without producing an audit message. The access decision is returned in +.I avd +and can be passed to +.BR avc_audit () +explicitly. + +.BR avc_audit () +produces an audit message for the access query represented by +.IR ssid , +.IR tsid , +.IR tclass , +and +.IR requested , +with a decision represented by +.IR avd . +Pass the value returned by +.BR avc_has_perm_noaudit () +as +.IR result . +The +.I auditdata +parameter is passed to the user-supplied +.B func_audit +callback and can be used to add supplemental information to the audit message; see +.BR avc_init (3). +. +.SH "ENTRY REFERENCES" +Entry references can be used to speed cache performance for repeated queries on the same subject and target. The userspace AVC will check the +.I aeref +argument, if supplied, before searching the cache on a permission query. After a query is performed, +.I aeref +will be updated to reference the cache entry for that query. A subsequent query on the same subject and target will then have the decision at hand without having to walk the cache. + +After declaring an +.B avc_entry_ref +structure, use +.BR avc_entry_ref_init () +to initialize it before passing it to +.BR avc_has_perm () +or +.BR \%avc_has_perm_noaudit () +for the first time. +Using an uninitialized structure will produce undefined behavior. +. +.SH "RETURN VALUE" +If requested permissions are granted, zero is returned. If requested permissions are denied or an error occurred, \-1 is returned and +.I errno +is set appropriately. + +In permissive mode, zero will be returned and +.I errno +unchanged even if permissions were denied. +.BR avc_has_perm () +will still produce an audit message in this case. +. +.SH "ERRORS" +.TP +.B EACCES +A requested permission was denied. +.TP +.B EINVAL +The +.I tclass +and/or the security contexts referenced by +.I ssid +and +.I tsid +are not recognized by the currently loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "NOTES" +Internal errors encountered by the userspace AVC may cause certain values of +.I errno +to be returned unexpectedly. For example, netlink socket errors may produce +.B EACCES +or +.BR EINVAL . +Make sure that userspace object managers are granted appropriate access to +netlink by the policy. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR security_compute_av (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_has_perm_noaudit.3 b/selinux/libselinux/man/man3/avc_has_perm_noaudit.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/selinux/libselinux/man/man3/avc_has_perm_noaudit.3
@@ -0,0 +1 @@ +.so man3/avc_has_perm.3
diff --git a/selinux/libselinux/man/man3/avc_init.3 b/selinux/libselinux/man/man3/avc_init.3 new file mode 100644 index 0000000..e26c3be --- /dev/null +++ b/selinux/libselinux/man/man3/avc_init.3
@@ -0,0 +1,196 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_init" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_init \- legacy userspace SELinux AVC setup +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_init(const char *" msgprefix , +.in +\w'int avc_init('u +.BI "const struct avc_memory_callback *" mem_callbacks , +.br +.BI "const struct avc_log_callback *" log_callbacks , +.br +.BI "const struct avc_thread_callback *" thread_callbacks , +.br +.BI "const struct avc_lock_callback *" lock_callbacks ");" +. +.SH "DESCRIPTION" +.BR avc_init () +is deprecated; please use +.BR avc_open (3) +in conjunction with +.BR selinux_set_callback (3) +in all new code. + +.BR avc_init () +initializes the userspace AVC and must be called before any other AVC operation can be performed. A non-NULL +.I msgprefix +will be prepended to all audit messages produced by the userspace AVC. The default is `uavc'. The remaining arguments, if non-NULL, specify callbacks to be used by the userspace AVC. +. +.SH "CALLBACKS" +The userspace AVC can be directed how to perform memory allocation, logging, thread creation, and locking via callback functions passed to +.BR avc_init (). +The purpose of this functionality is to allow the userspace AVC to be smoothly integrated into existing userspace object managers. + +Use an +.B avc_memory_callback +structure to specify alternate functions for dynamic memory allocation. + +.RS +.ta 4n 10n 24n +.nf +struct avc_memory_callback { + void *(*func_malloc)(size_t size); + void (*func_free)(void *ptr); +}; +.fi +.ta +.RE + +The two fields of the structure should be pointers to functions which behave as +.BR malloc (3) +and +.BR free (3), +which are used by default. + +Use an +.B avc_log_callback +structure to specify alternate functions for logging. + +.RS +.ta 4n 10n 24n +.nf +struct avc_log_callback { + void (*func_log)(const char *fmt, ...); + void (*func_audit)(void *auditdata, + security_class_t class, + char *msgbuf, size_t msgbufsize); +}; +.fi +.ta +.RE + +The +.B func_log +callback should accept a +.BR printf (3) +style format and arguments and log them as desired. The default behavior prints the message on the standard error. The +.B func_audit +callback should interpret the +.I auditdata +parameter for the given +.IR class , +printing a human-readable interpretation to +.I msgbuf +using no more than +.I msgbufsize +characters. The default behavior is to ignore +.IR auditdata . + +Use an +.B avc_thread_callback +structure to specify functions for starting and manipulating threads. + +.RS +.ta 4n 10n 24n +.nf +struct avc_thread_callback { + void *(*func_create_thread)(void (*run)(void)); + void (*func_stop_thread)(void *thread); +}; +.fi +.ta +.RE + +The +.B func_create_thread +callback should create a new thread and return a pointer which references it. The thread should execute the +.I run +argument, which does not return under normal conditions. The +.B func_stop_thread +callback should cancel the running thread referenced by +.IR thread . +By default, threading is not used; see +.B NETLINK NOTIFICATION +below. + +Use an +.B avc_lock_callback +structure to specify functions to create, obtain, and release locks for use by threads. + +.RS +.ta 4n 10n 24n +.nf +struct avc_lock_callback { + void *(*func_alloc_lock)(void); + void (*func_get_lock)(void *lock); + void (*func_release_lock)(void *lock); + void (*func_free_lock)(void *lock); +}; +.fi +.ta +.RE + +The +.B func_alloc_lock +callback should create a new lock, returning a pointer which references it. The +.B func_get_lock +callback should obtain +.IR lock , +blocking if necessary. The +.B func_release_lock +callback should release +.IR lock . +The +.B func_free_lock +callback should destroy +.IR lock , +freeing any resources associated with it. The default behavior is not to perform any locking. Note that undefined behavior may result if threading is used without appropriate locking. +. +.SH "NETLINK NOTIFICATION" +Beginning with version 2.6.4, the Linux kernel supports SELinux status change notification via netlink. Two message types are currently implemented, indicating changes to the enforcing mode and to the loaded policy in the kernel, respectively. The userspace AVC listens for these messages and takes the appropriate action, modifying the behavior of +.BR avc_has_perm (3) +to reflect the current enforcing mode and flushing the cache on receipt of a policy load notification. Audit messages are produced when netlink notifications are processed. + +In the default single-threaded mode, the userspace AVC checks for new netlink messages at the start of each permission query. If threading and locking callbacks are passed to +.BR avc_init () +however, a dedicated thread will be started to listen on the netlink socket. This may increase performance and will ensure that log messages are generated immediately rather than at the time of the next permission query. +. +.SH "RETURN VALUE" +Functions with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "NOTES" +The +.I msgprefix +argument to +.BR avc_init () +currently has a length limit of 15 characters and will be truncated if necessary. + +If a provided +.B func_malloc +callback does not set +.I errno +appropriately on error, userspace AVC calls may exhibit the +same behavior. + +If a netlink thread has been created and an error occurs on the socket (such as an access error), the thread may terminate and cause the userspace AVC to return +.B EINVAL +on all further permission checks until +.B avc_destroy +is called. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR avc_open (3), +.BR selinux_set_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_netlink_acquire_fd.3 b/selinux/libselinux/man/man3/avc_netlink_acquire_fd.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_acquire_fd.3
@@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3
diff --git a/selinux/libselinux/man/man3/avc_netlink_check_nb.3 b/selinux/libselinux/man/man3/avc_netlink_check_nb.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_check_nb.3
@@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3
diff --git a/selinux/libselinux/man/man3/avc_netlink_close.3 b/selinux/libselinux/man/man3/avc_netlink_close.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_close.3
@@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3
diff --git a/selinux/libselinux/man/man3/avc_netlink_loop.3 b/selinux/libselinux/man/man3/avc_netlink_loop.3 new file mode 100644 index 0000000..c8268a1 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_loop.3
@@ -0,0 +1,84 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: KaiGai Kohei (kaigai@ak.jp.nec.com) 2009 +.TH "avc_netlink_loop" "3" "30 Mar 2009" "" "SELinux API documentation" +.SH "NAME" +avc_netlink_open, avc_netlink_close, avc_netlink_acquire_fd, +avc_netlink_release_fd, avc_netlink_check_nb, avc_netlink_loop \- SELinux +netlink processing +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_netlink_open(int " blocking ");" +.sp +.B void avc_netlink_close(void); +.sp +.B int avc_netlink_acquire_fd(void); +.sp +.B void avc_netlink_release_fd(void); +.sp +.B void avc_netlink_loop(void); +.sp +.B int avc_netlink_check_nb(void); +. +.SH "DESCRIPTION" +These functions enable applications to handle notification of SELinux events +via netlink. The userspace AVC normally checks for netlink messages on each +call to +.BR avc_has_perm (3). +Applications may wish to override this behavior and check for notification +separately, for example in a +.BR select (2) +loop. These functions also permit netlink monitoring without requiring a +call to +.BR avc_open (3). + +.BR avc_netlink_open () +opens a netlink socket to receive SELinux notifications. The socket +descriptor is stored internally; use +.BR avc_netlink_acquire_fd (3) +to take ownership of it in application code. The +.I blocking +argument controls whether the O_NONBLOCK flag is set on the socket descriptor. +.BR avc_open (3) +calls this function internally, specifying non-blocking behavior. + +.BR avc_netlink_close () +closes the netlink socket. This function is called automatically by +.BR avc_destroy (3). + +.BR avc_netlink_acquire_fd () +returns the netlink socket descriptor number and informs the userspace AVC +not to check the socket descriptor automatically on calls to +.BR avc_has_perm (3). + +.BR avc_netlink_release_fd () +returns control of the netlink socket to the userspace AVC, re-enabling +automatic processing of notifications. + +.BR avc_netlink_check_nb () +checks the netlink socket for pending messages and processes them. +Callbacks for policyload and enforcing changes will be called; +see +.BR selinux_set_callback (3). +This function does not block. + +.BR avc_netlink_loop () +enters a loop blocking on the netlink socket and processing messages as they +are received. This function will not return unless an error occurs on +the socket, in which case the socket is closed. +. +.SH "RETURN VALUE" +.BR avc_netlink_acquire_fd () +returns a non-negative file descriptor number on success. Other functions +with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR avc_open (3), +.BR selinux_set_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/avc_netlink_open.3 b/selinux/libselinux/man/man3/avc_netlink_open.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_open.3
@@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3
diff --git a/selinux/libselinux/man/man3/avc_netlink_release_fd.3 b/selinux/libselinux/man/man3/avc_netlink_release_fd.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_netlink_release_fd.3
@@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3
diff --git a/selinux/libselinux/man/man3/avc_open.3 b/selinux/libselinux/man/man3/avc_open.3 new file mode 100644 index 0000000..5b275a8 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_open.3
@@ -0,0 +1,69 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2008 +.TH "avc_open" "3" "12 Jun 2008" "" "SELinux API documentation" +.SH "NAME" +avc_open, avc_destroy, avc_reset, avc_cleanup \- userspace SELinux AVC setup and teardown +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/avc.h> +.sp +.BI "int avc_open(struct selinux_opt *" options ", unsigned " nopt ");" +.sp +.BI "void avc_destroy(void);" +.sp +.BI "int avc_reset(void);" +.sp +.BI "void avc_cleanup(void);" +. +.SH "DESCRIPTION" +.BR avc_open () +initializes the userspace AVC and must be called before any other AVC operation can be performed. + +.BR avc_destroy () +destroys the userspace AVC, freeing all internal memory structures. After this call has been made, +.BR avc_open () +must be called again before any AVC operations can be performed. + +.BR avc_reset () +flushes the userspace AVC, causing it to forget any cached access decisions. The userspace AVC normally calls this function automatically when needed, see +.B NETLINK NOTIFICATION +below. + +.BR avc_cleanup () +attempts to free unused memory within the userspace AVC, but does not flush any cached access decisions. Under normal operation, calling this function should not be necessary. +.SH "OPTIONS" +The userspace AVC obeys callbacks set via +.BR selinux_set_callback (3), +in particular the logging and audit callbacks. + +The options which may be passed to +.BR avc_open () +include the following: +.TP +.B AVC_OPT_SETENFORCE +This option forces the userspace AVC into enforcing mode if the option value is non-NULL; permissive mode otherwise. The system enforcing mode will be ignored. +. +.SH "NETLINK NOTIFICATION" +Beginning with version 2.6.4, the Linux kernel supports SELinux status change notification via netlink. Two message types are currently implemented, indicating changes to the enforcing mode and to the loaded policy in the kernel, respectively. The userspace AVC listens for these messages and takes the appropriate action, modifying the behavior of +.BR avc_has_perm (3) +to reflect the current enforcing mode and flushing the cache on receipt of a policy load notification. Audit messages are produced when netlink notifications are processed. +. +.SH "RETURN VALUE" +Functions with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR selinux_set_callback (3), +.BR security_compute_av (3)
diff --git a/selinux/libselinux/man/man3/avc_reset.3 b/selinux/libselinux/man/man3/avc_reset.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/selinux/libselinux/man/man3/avc_reset.3
@@ -0,0 +1 @@ +.so man3/avc_open.3
diff --git a/selinux/libselinux/man/man3/avc_sid_stats.3 b/selinux/libselinux/man/man3/avc_sid_stats.3 new file mode 100644 index 0000000..6732dc1 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_sid_stats.3
@@ -0,0 +1 @@ +.so man3/avc_cache_stats.3
diff --git a/selinux/libselinux/man/man3/avc_sid_to_context.3 b/selinux/libselinux/man/man3/avc_sid_to_context.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/selinux/libselinux/man/man3/avc_sid_to_context.3
@@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3
diff --git a/selinux/libselinux/man/man3/checkPasswdAccess.3 b/selinux/libselinux/man/man3/checkPasswdAccess.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/checkPasswdAccess.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/context_free.3 b/selinux/libselinux/man/man3/context_free.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_free.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_new.3 b/selinux/libselinux/man/man3/context_new.3 new file mode 100644 index 0000000..3dabac3 --- /dev/null +++ b/selinux/libselinux/man/man3/context_new.3
@@ -0,0 +1,83 @@ +.TH "context_new" "3" "20 December 2011" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +context_new, context_str, context_free, context_type_get, context_type_set, context_range_get, context_range_set,context_role_get, context_role_set, context_user_get, context_user_set \- Routines to manipulate SELinux security contexts +. +.SH "SYNOPSIS" +.B #include <selinux/context.h> +.sp +.BI "context_t context_new(const char *" context_str ); +.sp +.BI "const char * context_str(context_t " con ); +.sp +.BI "void context_free(context_t " con ); +.sp +.BI "const char * context_type_get(context_t " con ); +.sp +.BI "const char * context_range_get(context_t " con ); +.sp +.BI "const char * context_role_get(context_t " con ); +.sp +.BI "const char * context_user_get(context_t " con ); +.sp +.BI "int context_type_set(context_t " con ", const char *" type ); +.sp +.BI "int context_range_set(context_t " con ", const char *" range ); +.sp +.BI "int context_role_set(context_t " con ", const char *" role ); +.sp +.BI "int context_user_set(context_t " con ", const char *" user ); +. +.SH "DESCRIPTION" +These functions allow an application to manipulate the fields of a +security context string without requiring it to know the format of the +string. + +.BR context_new () +returns a new context initialized to a context string. + +.BR context_str () +returns a pointer to the string value of the +.BR context_t , +valid until the next call to +.BR context_str () +or +.BR context_free () +for the same +.BR context_t* . + +.BR context_free () +frees the storage used by a context. + +.BR context_type_get (), +.BR context_range_get (), +.BR context_role_get (), +.BR \%context_user_get () +get a pointer to the string value of a context component. + +.B Note: +Values returned by the get functions are only valid until the next call +to a set function or +.BR context_free () +for the same +.B context_t +structure. + +.BR context_type_set (), +.BR context_range_set (), +.BR context_role_set (), +.BR \%context_user_set () +set a context component. +. +.SH "RETURN VALUE" +On failure +.BR context_*_set () +functions return non-zero and 0 on success. + +The other functions return NULL on failure and non-NULL on success. + +On failure +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/context_range_get.3 b/selinux/libselinux/man/man3/context_range_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_range_get.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_range_set.3 b/selinux/libselinux/man/man3/context_range_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_range_set.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_role_get.3 b/selinux/libselinux/man/man3/context_role_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_role_get.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_role_set.3 b/selinux/libselinux/man/man3/context_role_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_role_set.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_type_get.3 b/selinux/libselinux/man/man3/context_type_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_type_get.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_type_set.3 b/selinux/libselinux/man/man3/context_type_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_type_set.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_user_get.3 b/selinux/libselinux/man/man3/context_user_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_user_get.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/context_user_set.3 b/selinux/libselinux/man/man3/context_user_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/selinux/libselinux/man/man3/context_user_set.3
@@ -0,0 +1 @@ +.so man3/context_new.3
diff --git a/selinux/libselinux/man/man3/fgetfilecon.3 b/selinux/libselinux/man/man3/fgetfilecon.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/selinux/libselinux/man/man3/fgetfilecon.3
@@ -0,0 +1 @@ +.so man3/getfilecon.3
diff --git a/selinux/libselinux/man/man3/fgetfilecon_raw.3 b/selinux/libselinux/man/man3/fgetfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/selinux/libselinux/man/man3/fgetfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/getfilecon.3
diff --git a/selinux/libselinux/man/man3/fini_selinuxmnt.3 b/selinux/libselinux/man/man3/fini_selinuxmnt.3 new file mode 100644 index 0000000..d7805c9 --- /dev/null +++ b/selinux/libselinux/man/man3/fini_selinuxmnt.3
@@ -0,0 +1 @@ +.so man3/init_selinuxmnt.3
diff --git a/selinux/libselinux/man/man3/freecon.3 b/selinux/libselinux/man/man3/freecon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/freecon.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/freeconary.3 b/selinux/libselinux/man/man3/freeconary.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/freeconary.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/fsetfilecon.3 b/selinux/libselinux/man/man3/fsetfilecon.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/selinux/libselinux/man/man3/fsetfilecon.3
@@ -0,0 +1 @@ +.so man3/setfilecon.3
diff --git a/selinux/libselinux/man/man3/fsetfilecon_raw.3 b/selinux/libselinux/man/man3/fsetfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/selinux/libselinux/man/man3/fsetfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/setfilecon.3
diff --git a/selinux/libselinux/man/man3/get_default_context.3 b/selinux/libselinux/man/man3/get_default_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_default_context.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/get_default_context_with_level.3 b/selinux/libselinux/man/man3/get_default_context_with_level.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_default_context_with_level.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/get_default_context_with_role.3 b/selinux/libselinux/man/man3/get_default_context_with_role.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_default_context_with_role.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/get_default_context_with_rolelevel.3 b/selinux/libselinux/man/man3/get_default_context_with_rolelevel.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_default_context_with_rolelevel.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/get_default_type.3 b/selinux/libselinux/man/man3/get_default_type.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_default_type.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/get_ordered_context_list.3 b/selinux/libselinux/man/man3/get_ordered_context_list.3 new file mode 100644 index 0000000..b1dabb6 --- /dev/null +++ b/selinux/libselinux/man/man3/get_ordered_context_list.3
@@ -0,0 +1,108 @@ +.TH "get_ordered_context_list" "3" "1 January 2004" "russell@coker.com.au" "SELinux" +.SH "NAME" +get_ordered_context_list, get_ordered_context_list_with_level, get_default_context, get_default_context_with_level, get_default_context_with_role, get_default_context_with_rolelevel, query_user_context, manual_user_enter_context, get_default_role \- determine SELinux context(s) for user sessions +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/get_context_list.h> +.sp +.BI "int get_ordered_context_list(const char *" user ", char * "fromcon ", char ***" list ); +.sp +.BI "int get_ordered_context_list_with_level(const char *" user ", const char *" level ", char * "fromcon ", char ***" list ); +.sp +.BI "int get_default_context(const char *" user ", char * "fromcon ", char **" newcon ); +.sp +.BI "int get_default_context_with_level(const char *" user ", const char *" level ", char * "fromcon ", char **" newcon ); +.sp +.BI "int get_default_context_with_role(const char *" user ", const char *" role ", char * " fromcon ", char **" newcon "); +.sp +.BI "int get_default_context_with_rolelevel(const char *" user ", const char *" level ", const char *" role ", char * " fromcon ", char **" newcon "); +.sp +.BI "int query_user_context(char **" list ", char **" newcon ); +.sp +.BI "int manual_user_enter_context(const char *" user ", char **" newcon ); +.sp +.BI "int get_default_type(const char *" role ", char **" type ); +. +.SH "DESCRIPTION" +.BR get_ordered_context_list () +invokes the +.BR security_compute_user (3) +function to obtain the list of contexts for the specified +.I user +that are reachable from the specified +.I fromcon +context. The function then orders the resulting list based on the global +.I \%/etc/selinux/{SELINUXTYPE}/contexts/default_contexts +file and the per-user +.I \%/etc/selinux/{SELINUXTYPE}/contexts/users/<username> +file if it exists. The +.I fromcon +parameter may be NULL to indicate that the current context should +be used. The function returns the number of contexts in the +list, or \-1 upon errors. The list must be freed using the +.BR freeconary (3) +function. + +.BR get_ordered_context_list_with_level () +invokes the +.BR \%get_ordered_context_list () +function and applies the specified level. + +.BR get_default_context () +is the same as +.BR get_ordered_context_list () +but only returns a single context +which has to be freed with +.BR freecon (3). + +.BR get_default_context_with_level () +invokes the +.BR get_default_context () +function and applies the specified level. + +.BR get_default_context_with_role () +is the same as +.BR get_default_context () +but only returns a context with the specified role, returning \-1 if no +such context is reachable for the user. + +.BR get_default_context_with_rolelevel () +invokes the +.BR \%get_default_context_with_role () +function and applies the specified level. + +.BR query_user_context () +takes a list of contexts, queries the user via stdin/stdout as to which context +they want, and returns a new context as selected by the user (which has to be +freed with +.BR freecon (3)). + +.BR manual_user_enter_context () +allows the user to manually enter a context as a fallback if a list of +authorized contexts could not be obtained. Caller must free via +.BR freecon (3). + +.BR get_default_type () +Get the default type (domain) for +.I role +and set +.I type +to refer to it, which has to be freed with free. +. +.SH "RETURN VALUE" +.BR get_ordered_context_list () +and +.BR get_ordered_context_list_with_level () +return the number of contexts in the list upon success or \-1 upon errors. +The other functions return 0 for success or \-1 for errors. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux (8), +.BR freeconary (3), +.BR freecon (3), +.BR security_compute_av (3), +.BR getseuserbyname (3)
diff --git a/selinux/libselinux/man/man3/get_ordered_context_list_with_level.3 b/selinux/libselinux/man/man3/get_ordered_context_list_with_level.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/get_ordered_context_list_with_level.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/getcon.3 b/selinux/libselinux/man/man3/getcon.3 new file mode 100644 index 0000000..644ee47 --- /dev/null +++ b/selinux/libselinux/man/man3/getcon.3
@@ -0,0 +1,126 @@ +.TH "getcon" "3" "21 December 2011" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getcon, getprevcon, getpidcon \- get SELinux security context of a process + +freecon, freeconary \- free memory associated with SELinux security contexts + +getpeercon \- get security context of a peer socket + +setcon \- set current security context of a process +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getcon(char **" context ); +.sp +.BI "int getcon_raw(char **" context ); +.sp +.BI "int getprevcon(char **" context ); +.sp +.BI "int getprevcon_raw(char **" context ); +.sp +.BI "int getpidcon(pid_t " pid ", char **" context ); +.sp +.BI "int getpidcon_raw(pid_t " pid ", char **" context ); +.sp +.BI "int getpeercon(int " fd ", char **" context ); +.sp +.BI "int getpeercon_raw(int " fd ", char **" context ); +.sp +.BI "void freecon(char * "con ); +.sp +.BI "void freeconary(char **" con ); +.sp +.BI "int setcon(char * " context ); +.sp +.BI "int setcon_raw(char * " context ); +. +.SH "DESCRIPTION" +.BR getcon () +retrieves the context of the current process, which must be free'd with +freecon. + +.BR getprevcon () +same as getcon but gets the context before the last exec. + +.BR getpidcon () +returns the process context for the specified PID. + +.BR getpeercon () +retrieves context of peer socket, and set +.BI * context +to refer to it, which must be free'd with +.BR freecon (). + +.BR freecon () +frees the memory allocated for a security context. + +.BR freeconary () +frees the memory allocated for a context array. + +If +.I con +is NULL, no operation is performed. + +.BR setcon () +sets the current security context of the process to a new value. Note +that use of this function requires that the entire application be +trusted to maintain any desired separation between the old and new +security contexts, unlike exec-based transitions performed via +.BR setexeccon (3). +When possible, decompose your application and use +.BR setexeccon (3) +and +.BR execve (3) +instead. + +Since access to file descriptors is revalidated upon use by SELinux, +the new context must be explicitly authorized in the policy to use the +descriptors opened by the old context if that is desired. Otherwise, +attempts by the process to use any existing descriptors (including +.IR stdin , +.IR stdout , +and +.IR stderr ) +after performing the +.BR setcon () +will fail. + +A multi-threaded application can perform a +.BR setcon () +prior to creating +any child threads, in which case all of the child threads will inherit +the new context. However, prior to Linux 2.6.28, +.BR setcon () +would fail if there are any other +threads running in the same process since this would yield +an inconsistency among the security contexts of threads sharing +the same memory space. Since Linux 2.6.28, +.BR setcon() +is permitted for threads within a multi-threaded process if the +new security context is bounded by the old security context, where +the bounded relation is defined through typebounds statements in the +policy and guarantees that the new security context has a subset of +the permissions of the old security context. + +If the process was being ptraced at the time of the +.BR setcon () +operation, ptrace permission will be revalidated against the new +context and the +.BR setcon () +will fail if it is not allowed by policy. + +.BR getcon_raw (), +.BR getprevcon_raw (), +.BR getpidcon_raw (), +.BR getpeercon_raw () +and +.BR setcon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. +. +.SH "RETURN VALUE" +On error \-1 is returned. On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " setexeccon "(3)"
diff --git a/selinux/libselinux/man/man3/getcon_raw.3 b/selinux/libselinux/man/man3/getcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getcon_raw.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getexeccon.3 b/selinux/libselinux/man/man3/getexeccon.3 new file mode 100644 index 0000000..73c9e49 --- /dev/null +++ b/selinux/libselinux/man/man3/getexeccon.3
@@ -0,0 +1,105 @@ +.TH "getexeccon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getexeccon, setexeccon \- get or set the SELinux security context used for executing a new process + +rpm_execcon \- run a helper for rpm in an appropriate security context +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getexeccon(char **" context ); +.sp +.BI "int getexeccon_raw(char **" context ); +.sp +.BI "int setexeccon(char * "context ); +.sp +.BI "int setexeccon_raw(char * "context ); +.sp +.BI "int setexecfilecon(const char *" filename ", const char *" fallback_type ); +.sp +.BI "int rpm_execcon(unsigned int " verified ", const char *" filename ", char *const " argv "[] , char *const " envp "[]); +. +.SH "DESCRIPTION" +.BR getexeccon () +retrieves the context used for executing a new process. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getexeccon () +sets +.BI * context +to NULL if no exec context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setexeccon () +sets the context used for the next +.BR execve (2) +call. +NULL can be passed to +.BR setexeccon () +to reset to the default policy behavior. +The exec context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setexeccon () +can be applied prior to library +functions that internally perform an +.BR execve (2), +e.g. +.BR execl *(3), +.BR execv *(3), +.BR popen (3), +in order to set an exec context for that operation. + +.BR getexeccon_raw () +and +.BR setexeccon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform an +.BR execve (2) +must take care to +save, reset, and restore the exec context to avoid unexpected behavior. + +.BR setexecfilecon () +sets the context used for the next +.BR execve (2) +call, based on the policy for the +.IR filename , +and falling back to a new context with a +.I fallback_type +in case there is no transition. + +.BR rpm_execcon () +is deprecated; please use +.BR setexecfilecon () +in conjunction with +.BR execve (2) +in all new code. This function +runs a helper for rpm in an appropriate security context. The +verified parameter should contain the return code from the signature +verification (0 == ok, 1 == notfound, 2 == verifyfail, 3 == +nottrusted, 4 == nokey), although this information is not yet used by +the function. The function determines the proper security context for +the helper based on policy, sets the exec context accordingly, and +then executes the specified filename with the provided argument and +environment arrays. +. +.SH "RETURN VALUE" +On error \-1 is returned. + +On success +.BR getexeccon (), +.BR setexeccon () +and +.BR setexecfilecon () +return 0. +.BR rpm_execcon () +only returns upon errors, as it calls +.BR execve (2). +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3)"
diff --git a/selinux/libselinux/man/man3/getexeccon_raw.3 b/selinux/libselinux/man/man3/getexeccon_raw.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/selinux/libselinux/man/man3/getexeccon_raw.3
@@ -0,0 +1 @@ +.so man3/getexeccon.3
diff --git a/selinux/libselinux/man/man3/getfilecon.3 b/selinux/libselinux/man/man3/getfilecon.3 new file mode 100644 index 0000000..5bb575b --- /dev/null +++ b/selinux/libselinux/man/man3/getfilecon.3
@@ -0,0 +1,72 @@ +.TH "getfilecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getfilecon, fgetfilecon, lgetfilecon \- get SELinux security context of a file +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getfilecon(const char *" path ", char **" con ); +.sp +.BI "int getfilecon_raw(const char *" path ", char **" con ); +.sp +.BI "int lgetfilecon(const char *" path ", char **" con ); +.sp +.BI "int lgetfilecon_raw(const char *" path ", char **" con ); +.sp +.BI "int fgetfilecon(int "fd ", char **" con ); +.sp +.BI "int fgetfilecon_raw(int "fd ", char **" con ); +. +.SH "DESCRIPTION" +.BR getfilecon () +retrieves the context associated with the given path in the file system, the +length of the context is returned. + +.BR lgetfilecon () +is identical to +.BR getfilecon (), +except in the case of a symbolic link, where the +link itself is interrogated, not the file that it refers to. + +.BR fgetfilecon () +is identical to +.BR getfilecon (), +only the open file pointed to by filedes (as returned by +.BR open (2)) +is interrogated in place of path. + +.BR getfilecon_raw (), +.BR lgetfilecon_raw () +and +.BR fgetfilecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +The returned context should be freed with +.BR freecon (3) +if non-NULL. +. +.SH "RETURN VALUE" +On success, a positive number is returned indicating the size of the +extended attribute value. On failure, \-1 is returned and +.I errno +is set appropriately. + +If the context does not exist, or the process has no access to +this attribute, +.I errno +is set to +.BR ENODATA . + +If extended attributes are not supported by the filesystem, or are +disabled, +.I errno +is set to +.BR ENOTSUP . + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/getfilecon_raw.3 b/selinux/libselinux/man/man3/getfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/selinux/libselinux/man/man3/getfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/getfilecon.3
diff --git a/selinux/libselinux/man/man3/getfscreatecon.3 b/selinux/libselinux/man/man3/getfscreatecon.3 new file mode 100644 index 0000000..8cc4df5 --- /dev/null +++ b/selinux/libselinux/man/man3/getfscreatecon.3
@@ -0,0 +1,62 @@ +.TH "getfscreatecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getfscreatecon, setfscreatecon \- get or set the SELinux security context used for creating a new file system object +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getfscreatecon(char **" con ); +.sp +.BI "int getfscreatecon_raw(char **" con ); +.sp +.BI "int setfscreatecon(char * "context ); +.sp +.BI "int setfscreatecon_raw(char * "context ); +. +.SH "DESCRIPTION" +.BR getfscreatecon () +retrieves the context used for creating a new file system object. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getfscreatecon () +sets *con to NULL if no fscreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setfscreatecon () +sets the context used for creating a new file system object. +NULL can be passed to +.BR setfscreatecon () +to reset to the default policy behavior. +The fscreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setfscreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getfscreatecon_raw () +and +.BR setfscreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setfscreatecon () +must take care to +save, reset, and restore the fscreate context to avoid unexpected behavior. +. + +.br +.B Note: +Contexts are thread specific. + +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3), " getexeccon "(3)"
diff --git a/selinux/libselinux/man/man3/getfscreatecon_raw.3 b/selinux/libselinux/man/man3/getfscreatecon_raw.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/selinux/libselinux/man/man3/getfscreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getfscreatecon.3
diff --git a/selinux/libselinux/man/man3/getkeycreatecon.3 b/selinux/libselinux/man/man3/getkeycreatecon.3 new file mode 100644 index 0000000..b51008d --- /dev/null +++ b/selinux/libselinux/man/man3/getkeycreatecon.3
@@ -0,0 +1,61 @@ +.TH "getkeycreatecon" "3" "9 September 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getkeycreatecon, setkeycreatecon \- get or set the SELinux security context used for creating a new kernel keyrings +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getkeycreatecon(char **" con ); +.sp +.BI "int getkeycreatecon_raw(char **" con ); +.sp +.BI "int setkeycreatecon(char * "context ); +.sp +.BI "int setkeycreatecon_raw(char * "context ); +. +.SH "DESCRIPTION" +.BR getkeycreatecon () +retrieves the context used for creating a new kernel keyring. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getkeycreatecon () +sets *con to NULL if no keycreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setkeycreatecon () +sets the context used for creating a new kernel keyring. +NULL can be passed to +.BR setkeycreatecon () +to reset to the default policy behavior. +The keycreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setkeycreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getkeycreatecon_raw () +and +.BR setkeycreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setkeycreatecon () +must take care to +save, reset, and restore the keycreate context to avoid unexpected behavior. + +.br +.B Note: +Contexts are thread specific. +. +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3), " getexeccon "(3)"
diff --git a/selinux/libselinux/man/man3/getkeycreatecon_raw.3 b/selinux/libselinux/man/man3/getkeycreatecon_raw.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/selinux/libselinux/man/man3/getkeycreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getkeycreatecon.3
diff --git a/selinux/libselinux/man/man3/getpeercon.3 b/selinux/libselinux/man/man3/getpeercon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getpeercon.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getpeercon_raw.3 b/selinux/libselinux/man/man3/getpeercon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getpeercon_raw.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getpidcon.3 b/selinux/libselinux/man/man3/getpidcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getpidcon.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getpidcon_raw.3 b/selinux/libselinux/man/man3/getpidcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getpidcon_raw.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getprevcon.3 b/selinux/libselinux/man/man3/getprevcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getprevcon.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getprevcon_raw.3 b/selinux/libselinux/man/man3/getprevcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/getprevcon_raw.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/getseuserbyname.3 b/selinux/libselinux/man/man3/getseuserbyname.3 new file mode 100644 index 0000000..c231e65 --- /dev/null +++ b/selinux/libselinux/man/man3/getseuserbyname.3
@@ -0,0 +1,33 @@ +.TH "getseuserbyname" "3" "29 September 2005" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getseuserbyname \- get SELinux username and level for a given Linux username +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getseuserbyname(const char *" linuxuser ", char **" selinuxuser ", char **" level "); +. +.SH "DESCRIPTION" +.BR getseuserbyname () +retrieves the SELinux username and security level associated with +a given Linux username. The SELinux username and security level can +then be passed to other libselinux functions such as +.BR \%get_ordered_context_list_with_level (3) +and +.BR \%get_default_context_with_level (3). + +The returned SELinux username and level should be freed by the caller +using free. +. +.SH "RETURN VALUE" +On success, 0 is returned. +On failure, \-1 is returned and +.I errno +is set appropriately. + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/getsockcreatecon.3 b/selinux/libselinux/man/man3/getsockcreatecon.3 new file mode 100644 index 0000000..26086d9 --- /dev/null +++ b/selinux/libselinux/man/man3/getsockcreatecon.3
@@ -0,0 +1,62 @@ +.TH "getsockcreatecon" "3" "24 September 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getsockcreatecon, setsockcreatecon \- get or set the SELinux security context used for creating a new labeled sockets +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int getsockcreatecon(char **" con ); +.sp +.BI "int getsockcreatecon_raw(char **" con ); +.sp +.BI "int setsockcreatecon(char * "context ); +.sp +.BI "int setsockcreatecon_raw(char * "context ); +. +.SH "DESCRIPTION" +.BR getsockcreatecon () +retrieves the context used for creating a new labeled network socket. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getsockcreatecon () +sets *con to NULL if no sockcreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setsockcreatecon () +sets the context used for creating a new labeled network sockets +NULL can be passed to +.BR setsockcreatecon () +to reset to the default policy behavior. +The sockcreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setsockcreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getsockcreatecon_raw () +and +.BR setsockcreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setsockcreatecon () +must take care to +save, reset, and restore the sockcreate context to avoid unexpected behavior. +. + +.br +.B Note: +Contexts are thread specific. + +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3)
diff --git a/selinux/libselinux/man/man3/getsockcreatecon_raw.3 b/selinux/libselinux/man/man3/getsockcreatecon_raw.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/selinux/libselinux/man/man3/getsockcreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getsockcreatecon.3
diff --git a/selinux/libselinux/man/man3/init_selinuxmnt.3 b/selinux/libselinux/man/man3/init_selinuxmnt.3 new file mode 100644 index 0000000..8466f9f --- /dev/null +++ b/selinux/libselinux/man/man3/init_selinuxmnt.3
@@ -0,0 +1,31 @@ +.TH "init_selinuxmnt" "3" "21 Nov 2009" "" "SELinux API documentation" +.SH "NAME" +init_selinuxmnt \- initialize the global variable selinux_mnt +. +.SH "SYNOPSIS" +.BI "static void init_selinuxmnt(void);" +.sp +.BI "static void fini_selinuxmnt(void);" +.sp +.BI "void set_selinuxmnt(char *" mnt ");" +. +.SH "DESCRIPTION" +.BR init_selinuxmnt () +initializes the global variable +.I selinux_mnt +to the selinuxfs mountpoint. + +.BR fini_selinuxmnt () +deinitializes the global variable +.I selinux_mnt +that stores the selinuxfs mountpoint. + +.BR set_selinuxmnt () +changes the selinuxfs mountpoint to +.IR mnt . +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia <guido@trentalancia.com> +. +.SH "SEE ALSO" +.BR selinux (8),
diff --git a/selinux/libselinux/man/man3/is_context_customizable.3 b/selinux/libselinux/man/man3/is_context_customizable.3 new file mode 100644 index 0000000..7fed837 --- /dev/null +++ b/selinux/libselinux/man/man3/is_context_customizable.3
@@ -0,0 +1,24 @@ +.TH "is_context_customizable" "3" "10 January 2005" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +is_context_customizable \- check whether SELinux context type is customizable by the administrator +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int is_context_customizable(char * " scon ); +. +.SH "DESCRIPTION" +This function checks whether the type of scon is in the +.I /etc/selinux/{SELINUXTYPE}/context/customizable_types +file. A customizable type is a file context type that +administrators set on files, usually to allow certain domains to share the file content. restorecon and setfiles, by default, leave these context in place. +. +.SH "RETURN VALUE" +Returns 1 if security context is customizable or 0 if it is not. +Returns \-1 on error. +. +.SH "FILE" +.I /etc/selinux/{SELINUXTYPE}/context/customizable_types +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/is_selinux_enabled.3 b/selinux/libselinux/man/man3/is_selinux_enabled.3 new file mode 100644 index 0000000..b2df562 --- /dev/null +++ b/selinux/libselinux/man/man3/is_selinux_enabled.3
@@ -0,0 +1,24 @@ +.TH "is_selinux_enabled" "3" "7 Mar 2010" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +is_selinux_enabled \- check whether SELinux is enabled +. +.SH "NAME" +is_selinux_mls_enabled \- check whether SELinux is enabled for (Multi Level Security) MLS +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.B int is_selinux_enabled(); +.sp +.B int is_selinux_mls_enabled(); +. +.SH "DESCRIPTION" +.BR is_selinux_enabled () +returns 1 if SELinux is running or 0 if it is not. +On error, \-1 is returned. + +.BR is_selinux_mls_enabled () +returns 1 if SELinux is running in MLS mode or 0 if it is not. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/is_selinux_mls_enabled.3 b/selinux/libselinux/man/man3/is_selinux_mls_enabled.3 new file mode 100644 index 0000000..2817639 --- /dev/null +++ b/selinux/libselinux/man/man3/is_selinux_mls_enabled.3
@@ -0,0 +1 @@ +.so man3/is_selinux_enabled.3
diff --git a/selinux/libselinux/man/man3/lgetfilecon.3 b/selinux/libselinux/man/man3/lgetfilecon.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/selinux/libselinux/man/man3/lgetfilecon.3
@@ -0,0 +1 @@ +.so man3/getfilecon.3
diff --git a/selinux/libselinux/man/man3/lgetfilecon_raw.3 b/selinux/libselinux/man/man3/lgetfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/selinux/libselinux/man/man3/lgetfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/getfilecon.3
diff --git a/selinux/libselinux/man/man3/lsetfilecon.3 b/selinux/libselinux/man/man3/lsetfilecon.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/selinux/libselinux/man/man3/lsetfilecon.3
@@ -0,0 +1 @@ +.so man3/setfilecon.3
diff --git a/selinux/libselinux/man/man3/lsetfilecon_raw.3 b/selinux/libselinux/man/man3/lsetfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/selinux/libselinux/man/man3/lsetfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/setfilecon.3
diff --git a/selinux/libselinux/man/man3/manual_user_enter_context.3 b/selinux/libselinux/man/man3/manual_user_enter_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/manual_user_enter_context.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/matchmediacon.3 b/selinux/libselinux/man/man3/matchmediacon.3 new file mode 100644 index 0000000..187e1c1 --- /dev/null +++ b/selinux/libselinux/man/man3/matchmediacon.3
@@ -0,0 +1,30 @@ +.TH "matchmediacon" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +matchmediacon \- get the default SELinux security context for the specified mediatype from the policy +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int matchmediacon(const char *" media ", char **" con ); +. +.SH "DESCRIPTION" +.BR matchmediacon () +matches the specified media type with the media contexts configuration and +sets the security context +.I con +to refer to the resulting context. +.sp +.B Note: +Caller must free returned security context +.I con +using +.BR freecon (3). +. +.SH "RETURN VALUE" +Returns 0 on success or \-1 otherwise. +. +.SH Files +.I /etc/selinux/{POLICYTYPE}/contexts/files/media +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3)
diff --git a/selinux/libselinux/man/man3/matchpathcon.3 b/selinux/libselinux/man/man3/matchpathcon.3 new file mode 100644 index 0000000..177f15d --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon.3
@@ -0,0 +1,127 @@ +.TH "matchpathcon" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +matchpathcon, matchpathcon_index \- get the default SELinux security context for the specified path from the file contexts configuration +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int matchpathcon_init(const char *" path ");" +.sp +.BI "int matchpathcon_init_prefix(const char *" path ", const char *" prefix ");" +.sp +.BI "int matchpathcon_fini(void);" +.sp +.BI "int matchpathcon(const char *" path ", mode_t " mode ", char **" con "); +.sp +.BI "int matchpathcon_index(const char *" name ", mode_t " mode ", char **" con ");" +. +.SH "DESCRIPTION" + +This family of functions is deprecated. For new code, please use +.BR selabel_open (3) +with the +.B SELABEL_CTX_FILE +backend in place of +.BR matchpathcon_init (), +use +.BR selabel_close (3) +in place of +.BR matchpathcon_fini (), +and use +.BR selabel_lookup (3) +in place of +.BR matchpathcon (). + +The remaining description below is for the legacy interface. + +.BR matchpathcon_init () +loads the file contexts configuration specified by +.I path +into memory for use by subsequent +.BR matchpathcon () +calls. If +.I path +is NULL, then the active file contexts configuration is loaded by default, +i.e. the path returned by +.BR selinux_file_context_path (3). +Unless the +.B MATCHPATHCON_BASEONLY +flag has been set via +.BR \%set_matchpathcon_flags (3), +files with the same path prefix but a +.B \%.homedirs +and +.B .local +suffix are also looked up and loaded if present. These files provide +dynamically generated entries for user home directories and for local +customizations. + +.BR matchpathcon_init_prefix () +is the same as +.BR matchpathcon_init () +but only loads entries with regular expressions whose first pathname +component is a prefix of +.I \%prefix +, e.g. pass "/dev" if you only intend to call +.BR matchpathcon () +with pathnames beginning with /dev. +However, this optimization is no longer necessary due to the use of +.I file_contexts.bin +files with precompiled regular expressions, so use of this interface +is deprecated. + +.BR matchpathcon_fini () +frees the memory allocated by a prior call to +.BR matchpathcon_init. () +This function can be used to free and reset the internal state between multiple +.BR matchpathcon_init () +calls, or to free memory when finished using +.BR matchpathcon (). + +.BR matchpathcon () +matches the specified +.I pathname, +after transformation via +.BR realpath (3) +excepting any final symbolic link component if S_IFLNK was +specified as the +.I mode, +and +.I mode +against the +.I file contexts +configuration and sets the security context +.I con +to refer to the +resulting context. The caller must free the returned security context +.I con +using +.BR freecon (3) +when finished using it. +.I mode +can be 0 to disable mode matching, but +should be provided whenever possible, as it may affect the matching. +Only the file format bits (i.e. the file type) of the +.I mode +are used. +If +.BR matchpathcon_init () +has not already been called, then this function will call it upon +its first invocation with a NULL +.I path, +defaulting to the active file contexts configuration. + +.BR matchpathcon_index () +is the same as +.BR matchpathcon () +but returns a specification index that can later be used in a +.BR matchpathcon_filespec_add (3) +call. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " set_matchpathcon_flags "(3), " set_matchpathcon_invalidcon "(3), " set_matchpathcon_printf "(3), " matchpathcon_filespec_add "(3), " matchpathcon_checkmatches "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/matchpathcon_checkmatches.3 b/selinux/libselinux/man/man3/matchpathcon_checkmatches.3 new file mode 100644 index 0000000..6bbee44 --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_checkmatches.3
@@ -0,0 +1,48 @@ +.TH "matchpathcon_checkmatches" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +matchpathcon_checkmatches, matchpathcon_filespec_add, matchpathcon_filespec_destroy, matchpathcon_filespec_eval \- check and report whether any specification index has no matches with any inode. Maintenance and statistics on inode associations +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "void matchpathcon_checkmatches(char *" str ");" +.sp +.BI "int matchpathcon_filespec_add(ino_t " ino ", int " specind ", const char *" file ");" +.sp +.BI "void matchpathcon_filespec_destroy(void);" +.sp +.BI "void matchpathcon_filespec_eval(void);" +. +.SH "DESCRIPTION" +.BR matchpathcon_checkmatches () +checks whether any specification has no matches and reports them. +The +.I str +argument is used as a prefix for any warning messages. +.sp +.BR matchpathcon_filespec_add () +maintains an association between an inode +.I ino +and a specification index +.IR specind , +and checks whether a conflicting specification is already associated +with the same inode (e.g. due to multiple hard links). If so, then +it uses the latter of the two specifications based on their order in the +.I file +context configuration. Returns the specification index used or \-1 on +error. +.sp +.BR matchpathcon_filespec_destroy () +destroys any inode associations that have been added, e.g. to restart +for a new filesystem. +.sp +.BR matchpathcon_filespec_eval () +displays statistics on the hash table usage for the inode associations. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " matchpathcon "(3), " matchpathcon_index "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/matchpathcon_filespec_add.3 b/selinux/libselinux/man/man3/matchpathcon_filespec_add.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_filespec_add.3
@@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3
diff --git a/selinux/libselinux/man/man3/matchpathcon_filespec_destroy.3 b/selinux/libselinux/man/man3/matchpathcon_filespec_destroy.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_filespec_destroy.3
@@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3
diff --git a/selinux/libselinux/man/man3/matchpathcon_filespec_eval.3 b/selinux/libselinux/man/man3/matchpathcon_filespec_eval.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_filespec_eval.3
@@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3
diff --git a/selinux/libselinux/man/man3/matchpathcon_fini.3 b/selinux/libselinux/man/man3/matchpathcon_fini.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_fini.3
@@ -0,0 +1 @@ +.so man3/matchpathcon.3
diff --git a/selinux/libselinux/man/man3/matchpathcon_index.3 b/selinux/libselinux/man/man3/matchpathcon_index.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_index.3
@@ -0,0 +1 @@ +.so man3/matchpathcon.3
diff --git a/selinux/libselinux/man/man3/matchpathcon_init.3 b/selinux/libselinux/man/man3/matchpathcon_init.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/selinux/libselinux/man/man3/matchpathcon_init.3
@@ -0,0 +1 @@ +.so man3/matchpathcon.3
diff --git a/selinux/libselinux/man/man3/mode_to_security_class.3 b/selinux/libselinux/man/man3/mode_to_security_class.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/mode_to_security_class.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man3/print_access_vector.3 b/selinux/libselinux/man/man3/print_access_vector.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/print_access_vector.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man3/query_user_context.3 b/selinux/libselinux/man/man3/query_user_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/selinux/libselinux/man/man3/query_user_context.3
@@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3
diff --git a/selinux/libselinux/man/man3/rpm_execcon.3 b/selinux/libselinux/man/man3/rpm_execcon.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/selinux/libselinux/man/man3/rpm_execcon.3
@@ -0,0 +1 @@ +.so man3/getexeccon.3
diff --git a/selinux/libselinux/man/man3/security_av_perm_to_string.3 b/selinux/libselinux/man/man3/security_av_perm_to_string.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/security_av_perm_to_string.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man3/security_av_string.3 b/selinux/libselinux/man/man3/security_av_string.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/security_av_string.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man3/security_check_context.3 b/selinux/libselinux/man/man3/security_check_context.3 new file mode 100644 index 0000000..8ece48c --- /dev/null +++ b/selinux/libselinux/man/man3/security_check_context.3
@@ -0,0 +1,23 @@ +.TH "security_check_context" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_check_context \- check the validity of a SELinux context +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int security_check_context(char * "con ); +.sp +.BI "int security_check_context_raw(char * "con ); +. +.SH "DESCRIPTION" +.BR security_check_context () +returns 0 if SELinux is running and the context is valid, otherwise it +returns \-1. + +.BR security_check_context_raw () +behaves identically to +.BR \%security_check_context () +but does not perform context translation. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/security_check_context_raw.3 b/selinux/libselinux/man/man3/security_check_context_raw.3 new file mode 100644 index 0000000..ee93986 --- /dev/null +++ b/selinux/libselinux/man/man3/security_check_context_raw.3
@@ -0,0 +1 @@ +.so man3/security_check_context.3
diff --git a/selinux/libselinux/man/man3/security_class_to_string.3 b/selinux/libselinux/man/man3/security_class_to_string.3 new file mode 100644 index 0000000..1b1b88d --- /dev/null +++ b/selinux/libselinux/man/man3/security_class_to_string.3
@@ -0,0 +1,96 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "security_class_to_string" "3" "30 Mar 2007" "" "SELinux API documentation" +.SH "NAME" +security_class_to_string, security_av_perm_to_string, string_to_security_class, string_to_av_perm, security_av_string, mode_to_security_class \- convert +between SELinux class and permission values and string names. +. +print_access_vector \- display an access vector in human-readable form. +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "const char *security_class_to_string(security_class_t " tclass ");" +.sp +.BI "const char *security_av_perm_to_string(security_class_t " tclass ", access_vector_t " av ");" +.sp +.BI "int security_av_string(security_class_t " tclass ", access_vector_t " av ", char **" result ");" +.sp +.BI "security_class_t string_to_security_class(const char *" name ");" +.sp +.BI "security_class_t mode_to_security_class(mode_t " mode ");" +.sp +.BI "access_vector_t string_to_av_perm(security_class_t " tclass ", const char *" name ");" +.sp +.BI "void print_access_vector(security_class_t " tclass ", access_vector_t " av ");" +. +.SH "DESCRIPTION" +.BR security_class_to_string () +returns a string name for class +.IR tclass , +or NULL if the class is invalid. The returned string must not be modified or freed. + +.BR security_av_perm_to_string () +returns a string name for the access vector bit +.I av +of class +.IR tclass , +or NULL if either argument is invalid. The returned string must not be modified or freed. + +.BR security_av_string () +computes a full access vector string representation using +.I tclass +and +.IR av , +which may have multiple bits set. The string is returned in the memory pointed to by +.IR result , +and should be freed by the caller using +.BR free (3). + +.BR string_to_security_class () +returns the class value corresponding to the string name +.IR name , +or zero if no such class exists. + +.BR mode_to_security_class () +returns the class value corresponding to the specified +.IR mode , +or zero if no such class exists. + +.BR string_to_av_perm () +returns the access vector bit corresponding to the string name +.I name +and security class +.IR tclass , +or zero if no such value exists. + +.BR print_access_vector () +displays an access vector in human-readable form on the standard output +stream. +. +.SH "RETURN VALUE" +.BR security_av_string () +returns zero on success or \-1 on error with +.I errno +set appropriately. +.BR print_access_vector () +does not return a value. All other functions return zero or NULL on error. +. +.SH "ERRORS" +.TP +.B EINVAL +A class or access vector argument is not recognized by the currently loaded policy. + +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getcon (3), +.BR getfilecon (3) +.BR stat (3)
diff --git a/selinux/libselinux/man/man3/security_commit_booleans.3 b/selinux/libselinux/man/man3/security_commit_booleans.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/selinux/libselinux/man/man3/security_commit_booleans.3
@@ -0,0 +1 @@ +.so man3/security_load_booleans.3
diff --git a/selinux/libselinux/man/man3/security_compute_av.3 b/selinux/libselinux/man/man3/security_compute_av.3 new file mode 100644 index 0000000..a56c3c8 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_av.3
@@ -0,0 +1,138 @@ +.TH "security_compute_av" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_compute_av, security_compute_av_flags, security_compute_create, security_compute_create_name, security_compute_relabel, +security_compute_member, security_compute_user, security_get_initial_context \- query +the SELinux policy database in the kernel +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int security_compute_av(char * "scon ", char * "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_flags(char * "scon ", char * "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_flags_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_create(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_create_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_create_name(char * "scon ", char * "tcon ", security_class_t "tclass ", const char *"objname ", char **" newcon ); +.sp +.BI "int security_compute_create_name_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", const char *"objname ", char **" newcon ); +.sp +.BI "int security_compute_relabel(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_relabel_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_member(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_member_raw(char * "scon ", char * "tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_user(char * "scon ", const char *" username ", char ***" con ); +.sp +.BI "int security_compute_user_raw(char * "scon ", const char *" username ", char ***" con ); +.sp +.BI "int security_get_initial_context(const char *" name ", char **" con ); +.sp +.BI "int security_get_initial_context_raw(const char *" name ", char **" con ); +.sp +.BI "int selinux_check_access(const char * " scon ", const char * " tcon ", const char *" class ", const char *" perm ", void *" auditdata); +.sp +.BI "int selinux_check_passwd_access(access_vector_t " requested ); +.sp +.BI "int checkPasswdAccess(access_vector_t " requested ); +. +.SH "DESCRIPTION" +.BR security_compute_av () +queries whether the policy permits the source context +.I scon +to access the target context +.I tcon +via class +.I tclass +with the +.I requested +access vector. The decision is returned in +.IR avd . + +.BR security_compute_av_flags () +is identical to +.B security_compute_av +but additionally sets the +.I flags +field of +.IR avd . +Currently one flag is supported: +.BR SELINUX_AVD_FLAGS_PERMISSIVE , +which indicates the decision is computed on a permissive domain. + +.BR security_compute_create () +is used to compute a context to use for labeling a new object in a particular +class based on a SID pair. + +.BR security_compute_create_name () +is identical to +.BR \%security_compute_create () +but also takes name of the new object in creation as an argument. +When +.B TYPE_TRANSITION +rule on the given class and a SID pair has object name extension, +we shall be able to obtain a correct +.I newcon +according to the security policy. Note that this interface is only +supported on the linux 2.6.40 or later. +In the older kernel, the object name will be simply ignored. + +.BR security_compute_relabel () +is used to compute the new context to use when relabeling an object, it is used +in the pam_selinux.so source and the newrole source to determine the correct +label for the tty at login time, but can be used for other things. + +.BR security_compute_member () +is used to compute the context to use when labeling a polyinstantiated object +instance. + +.BR security_compute_user () +is used to determine the set of user contexts that can be reached from a +source context. It is mainly used by +.BR get_ordered_context_list (). + +.BR security_get_initial_context () +is used to get the context of a kernel initial security identifier specified by +.I name + +.BR security_compute_av_raw (), +.BR security_compute_av_flags_raw (), +.BR \%security_compute_create_raw (), +.BR \%security_compute_create_name_raw (), +.BR \%security_compute_relabel_raw (), +.BR \%security_compute_member_raw (), +.BR \%security_compute_user_raw () +and +.BR \%security_get_initial_context_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.BR selinux_check_access () +is used to check if the source context has the access permission for the specified class on the target context. + +.BR selinux_check_passwd_access () +is used to check for a permission in the +.I passwd +class. +.BR selinux_check_passwd_access () +uses getprevcon() for the source and target security contexts. + +.BR checkPasswdAccess () +is a deprecated alias of the +.BR selinux_check_passwd_access () +function. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 on error. +. +.SH "SEE ALSO" +.BR selinux "(8), " getcon "(3), " getfilecon "(3), " get_ordered_context_list "(3)"
diff --git a/selinux/libselinux/man/man3/security_compute_av_flags.3 b/selinux/libselinux/man/man3/security_compute_av_flags.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_av_flags.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_av_flags_raw.3 b/selinux/libselinux/man/man3/security_compute_av_flags_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_av_flags_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_av_raw.3 b/selinux/libselinux/man/man3/security_compute_av_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_av_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_create.3 b/selinux/libselinux/man/man3/security_compute_create.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_create.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_create_name.3 b/selinux/libselinux/man/man3/security_compute_create_name.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_create_name.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_create_name_raw.3 b/selinux/libselinux/man/man3/security_compute_create_name_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_create_name_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_create_raw.3 b/selinux/libselinux/man/man3/security_compute_create_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_create_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_member.3 b/selinux/libselinux/man/man3/security_compute_member.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_member.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_member_raw.3 b/selinux/libselinux/man/man3/security_compute_member_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_member_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_relabel.3 b/selinux/libselinux/man/man3/security_compute_relabel.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_relabel.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_relabel_raw.3 b/selinux/libselinux/man/man3/security_compute_relabel_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_relabel_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_user.3 b/selinux/libselinux/man/man3/security_compute_user.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_user.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_compute_user_raw.3 b/selinux/libselinux/man/man3/security_compute_user_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_compute_user_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_deny_unknown.3 b/selinux/libselinux/man/man3/security_deny_unknown.3 new file mode 100644 index 0000000..d59e5c2 --- /dev/null +++ b/selinux/libselinux/man/man3/security_deny_unknown.3
@@ -0,0 +1 @@ +.so man3/security_getenforce.3
diff --git a/selinux/libselinux/man/man3/security_disable.3 b/selinux/libselinux/man/man3/security_disable.3 new file mode 100644 index 0000000..072923c --- /dev/null +++ b/selinux/libselinux/man/man3/security_disable.3
@@ -0,0 +1,30 @@ +.TH "security_disable" "3" "21 Nov 2009" "" "SELinux API documentation" +.SH "NAME" +security_disable \- disable the SELinux kernel code at runtime +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int security_disable(void);" +. +.SH "DESCRIPTION" +.BR security_disable () +disables the SELinux kernel code, unregisters selinuxfs from +.IR /proc/filesystems , +and then unmounts +.IR /sys/fs/selinux . +.sp +This function can only be called at runtime and prior to the initial policy +load. After the initial policy load, the SELinux kernel code cannot be disabled, +but only placed in "permissive" mode by using +.BR security_setenforce(3). +. +.SH "RETURN VALUE" +.BR security_disable () +returns zero on success or \-1 on error. +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia <guido@trentalancia.com> +. +.SH "SEE ALSO" +.BR selinux (8), " setenforce "(8)
diff --git a/selinux/libselinux/man/man3/security_get_boolean_active.3 b/selinux/libselinux/man/man3/security_get_boolean_active.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/selinux/libselinux/man/man3/security_get_boolean_active.3
@@ -0,0 +1 @@ +.so man3/security_load_booleans.3
diff --git a/selinux/libselinux/man/man3/security_get_boolean_names.3 b/selinux/libselinux/man/man3/security_get_boolean_names.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/selinux/libselinux/man/man3/security_get_boolean_names.3
@@ -0,0 +1 @@ +.so man3/security_load_booleans.3
diff --git a/selinux/libselinux/man/man3/security_get_boolean_pending.3 b/selinux/libselinux/man/man3/security_get_boolean_pending.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/selinux/libselinux/man/man3/security_get_boolean_pending.3
@@ -0,0 +1 @@ +.so man3/security_load_booleans.3
diff --git a/selinux/libselinux/man/man3/security_get_initial_context.3 b/selinux/libselinux/man/man3/security_get_initial_context.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_get_initial_context.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_get_initial_context_raw.3 b/selinux/libselinux/man/man3/security_get_initial_context_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/security_get_initial_context_raw.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/security_getenforce.3 b/selinux/libselinux/man/man3/security_getenforce.3 new file mode 100644 index 0000000..7658014 --- /dev/null +++ b/selinux/libselinux/man/man3/security_getenforce.3
@@ -0,0 +1,29 @@ +.TH "security_getenforce" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_getenforce, security_setenforce, security_deny_unknown \- get or set the enforcing state of SELinux +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.B int security_getenforce(void); +.sp +.BI "int security_setenforce(int "value ); +.sp +.B int security_deny_unknown(void); +. +.SH "DESCRIPTION" +.BR security_getenforce () +returns 0 if SELinux is running in permissive mode, 1 if it is running in +enforcing mode, and \-1 on error. + +.BR security_setenforce () +sets SELinux to enforcing mode if the value 1 is passed in, and sets it to +permissive mode if 0 is passed in. On success 0 is returned, on error \-1 is +returned. + +.BR security_deny_unknown () +returns 0 if SELinux treats policy queries on undefined object classes or +permissions as being allowed, 1 if such queries are denied, and \-1 on error. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/security_load_booleans.3 b/selinux/libselinux/man/man3/security_load_booleans.3 new file mode 100644 index 0000000..3b0bbea --- /dev/null +++ b/selinux/libselinux/man/man3/security_load_booleans.3
@@ -0,0 +1,66 @@ +.TH "security_get_boolean_names" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API Documentation" +.SH "NAME" +security_load_booleans, security_set_boolean, security_commit_booleans, +security_get_boolean_names, security_get_boolean_active, +security_get_boolean_pending \- routines for manipulating SELinux boolean values +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int security_load_booleans(char *" path ");" +.sp +.BI "int security_get_boolean_names(char ***" names ", int *" len ");" +.sp +.BI "int security_get_boolean_pending(const char *" name ");" +.sp +.BI "int security_get_boolean_active(const char *" name ");" +.sp +.BI "int security_set_boolean(const char *" name ", int " value ");" +.sp +.BI "int security_set_boolean_list(size_t " boolcnt ", SELboolean *" boollist ", int " permanent ");" +.sp +.BI "int security_commit_booleans(void);" +. +.SH "DESCRIPTION" +The SELinux policy can include conditional rules that are enabled or +disabled based on the current values of a set of policy booleans. +These policy booleans allow runtime modification of the security +policy without having to load a new policy. + +The SELinux API allows for a transaction based update. So you can +set several boolean values and then commit them all at once. + +.BR security_load_booleans () +loads policy boolean settings. Path may be NULL, in which case the +booleans are loaded from the active policy boolean configuration file. + +.BR security_get_boolean_names () +provides a list of boolean names, currently supported by the loaded policy. + +.BR security_get_boolean_pending () +returns the pending value for boolean or \-1 on failure. + +.BR security_get_boolean_active () +returns the active value for boolean or \-1 on failure. + +.BR security_set_boolean () +sets the pending value for boolean + +.BR security_set_boolean_list () +saves a list of booleans in a single transaction. + +.BR security_commit_booleans () +commits all pending values for the booleans. +. +.SH "RETURN VALUE" +Where not otherwise stated, functions described in this manual page return +zero on success or \-1 on error. +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getsebool (8), +.BR booleans (8), +.BR togglesebool (8)
diff --git a/selinux/libselinux/man/man3/security_load_policy.3 b/selinux/libselinux/man/man3/security_load_policy.3 new file mode 100644 index 0000000..af56163 --- /dev/null +++ b/selinux/libselinux/man/man3/security_load_policy.3
@@ -0,0 +1,57 @@ +.TH "security_load_policy" "3" "3 November 2009" "guido@trentalancia.com" "SELinux API documentation" +.SH "NAME" +security_load_policy \- load a new SELinux policy +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int security_load_policy(void *" data ", size_t "len ); +.sp +.BI "int selinux_mkload_policy(int " preservebools ");" +.sp +.BI "int selinux_init_load_policy(int *" enforce ");" +. +.SH "DESCRIPTION" +.BR security_load_policy () +loads a new policy, returns 0 for success and \-1 for error. + +.BR selinux_mkload_policy () +makes a policy image and loads it. This function provides a higher level +interface for loading policy than +.BR \%security_load_policy (), +internally determining the right policy version, locating and opening +the policy file, mapping it into memory, manipulating it as needed for +current boolean settings and/or local definitions, and then calling +security_load_policy to load it. +.I preservebools +is a boolean flag indicating whether current policy boolean values should +be preserved into the new policy (if 1) or reset to the saved policy +settings (if 0). The former case is the default for policy reloads, while +the latter case is an option for policy reloads but is primarily used for +the initial policy load. +.BR selinux_init_load_policy () +performs the initial policy load. This function determines the desired +enforcing mode, sets the +.I enforce +argument accordingly for the caller to use, sets the SELinux kernel +enforcing status to match it, and loads the policy. It also internally +handles the initial selinuxfs mount required to perform these actions. +.sp +It should also be noted that after the initial policy load, the SELinux +kernel code cannot anymore be disabled and the selinuxfs cannot be +unmounted using a call to +.BR security_disable (3). +Therefore, after the initial policy load, the only operational changes +are those permitted by +.BR security_setenforce (3) +(i.e. eventually setting the framework in permissive mode rather than +in enforcing one). +. +.SH "RETURN VALUE" +Returns zero on success or \-1 on error. +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia <guido@trentalancia.com> +. +.SH "SEE ALSO" +.BR selinux "(8), " security_disable "(3), " setenforce "(8)
diff --git a/selinux/libselinux/man/man3/security_mkload_policy.3 b/selinux/libselinux/man/man3/security_mkload_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/selinux/libselinux/man/man3/security_mkload_policy.3
@@ -0,0 +1 @@ +.so man3/security_load_policy.3
diff --git a/selinux/libselinux/man/man3/security_policyvers.3 b/selinux/libselinux/man/man3/security_policyvers.3 new file mode 100644 index 0000000..041ff3a --- /dev/null +++ b/selinux/libselinux/man/man3/security_policyvers.3
@@ -0,0 +1,15 @@ +.TH "security_policyvers" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_policyvers \- get the version of the SELinux policy +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.B int security_policyvers(); +. +.SH "DESCRIPTION" +.BR security_policyvers () +returns the version of the policy (a positive integer) on success, or \-1 on +error. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/security_set_boolean.3 b/selinux/libselinux/man/man3/security_set_boolean.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/selinux/libselinux/man/man3/security_set_boolean.3
@@ -0,0 +1 @@ +.so man3/security_load_booleans.3
diff --git a/selinux/libselinux/man/man3/security_setenforce.3 b/selinux/libselinux/man/man3/security_setenforce.3 new file mode 100644 index 0000000..24bca10 --- /dev/null +++ b/selinux/libselinux/man/man3/security_setenforce.3
@@ -0,0 +1 @@ +.so security_getenforce.3
diff --git a/selinux/libselinux/man/man3/selabel_close.3 b/selinux/libselinux/man/man3/selabel_close.3 new file mode 100644 index 0000000..468fdaf --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_close.3
@@ -0,0 +1 @@ +.so man3/selabel_open.3
diff --git a/selinux/libselinux/man/man3/selabel_digest.3 b/selinux/libselinux/man/man3/selabel_digest.3 new file mode 100644 index 0000000..56a008f --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_digest.3
@@ -0,0 +1,61 @@ +.TH "selabel_digest" "3" "16 Sept 2015" "" "SELinux API documentation" +.SH "NAME" +selabel_digest \- Return digest of specfiles and list of files used +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "int selabel_digest(struct selabel_handle *" hnd , +.in +\w'int selabel_digest('u +.BI "unsigned char **" digest , +.BI "size_t *" digest_len , +.br +.BI "char ***" specfiles, +.BI "size_t *" num_specfiles ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_digest () +performs an operation on the handle +.IR hnd , +returning the results of the SHA1 digest pointed to by +.IR digest , +whose length will be +.IR digest_len . +The list of specfiles used in the SHA1 digest calculation is returned in +.I specfiles +with the number of entries in +.IR num_specfiles . +.sp +To enable +.BR selabel_digest () +to return this information the +.B SELABEL_OPT_DIGEST +option must be enable in +.BR selabel_open (3). +.sp +The result of +.BR selabel_digest () +must not be used after +.BR selabel_close (3). +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +No digest available (returned if +.B SELABEL_OPT_DIGEST +option not enabled). +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selabel_lookup.3 b/selinux/libselinux/man/man3/selabel_lookup.3 new file mode 100644 index 0000000..4e47c3e --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_lookup.3
@@ -0,0 +1,79 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_lookup" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_lookup \- obtain SELinux security context from a string label +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" key ", int " type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_raw('u +.BI "char **" context , +.br +.BI "const char *" key ", int " type ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_lookup () +performs a lookup operation on the handle +.IR hnd , +returning the result in the memory pointed to by +.IR context , +which must be freed by the caller using +.BR freecon (3). +The +.I key +and +.I type +parameters are the inputs to the lookup operation and are interpreted according to the specific backend that +.I handle +is open on. + +.BR selabel_lookup_raw () +behaves identically to +.BR selabel_lookup () +but does not perform context translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOENT +No context corresponding to the input +.I key +and +.I type +was found. +.TP +.B EINVAL +The +.I key +and/or +.I type +inputs are invalid, or the context being returned failed validation. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selabel_lookup_best_match.3 b/selinux/libselinux/man/man3/selabel_lookup_best_match.3 new file mode 100644 index 0000000..ef2efb4 --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_lookup_best_match.3
@@ -0,0 +1,100 @@ +.TH "selabel_lookup_best_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selabel_lookup_best_match \- obtain a best match SELinux security +context \- Only supported on file backend. +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup_best_match(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_best_match('u +.BI "char **" context , +.br +.BI "const char *" key , +.br +.BI "const char **" links , +.br +.BI "int " type ");" +.in +.sp +.BI "int selabel_lookup_best_match_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_best_match_raw('u +.BI "char **" context , +.br +.BI "const char *" key , +.br +.BI "const char **" links , +.br +.BI "int " type ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_lookup_best_match () +performs a best match lookup operation on the handle +.IR hnd , +returning the result in the memory pointed to by +.IR context , +which must be freed by the caller using +.BR freecon (3). +The \fIkey\fR parameter is a file path to check for best match using zero or +more \fIlink\fR (aliases) parameters. The order of precedence for best match is: +.RS +.IP "1." 4 +An exact match for the real path (\fIkey\fR) or +.IP "2." 4 +An exact match for any of the \fIlink\fRs (aliases), or +.IP "3." 4 +The longest fixed prefix match. +.RE +.sp +The \fItype\fR parameter is an optional file \fImode\fR argument that should +be set to the mode bits of the file, as determined by \fBlstat\fR(2). +\fImode\fR may be zero, however full matching may not occur. + +.BR selabel_lookup_best_match_raw () +behaves identically to +.BR selabel_lookup_best_match () +but does not perform context translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOENT +No context corresponding to the input +.I key +and +.I type +was found. +.TP +.B EINVAL +The +.I key +and/or +.I type +inputs are invalid, or the context being returned failed validation. +.TP +.B ENOMEM +An attempt to allocate memory failed. +.sp +.SH "NOTES" +Example usage - When a service creates a device node, it may also create one +or more symlinks to the device node. These symlinks may be the only stable +name for the device, e.g. if the partition is dynamically assigned. +The file label backend supports this by looking up the "best match" +for a device node based on its real path (\fIkey\fR) and any \fIlink\fRs to it +(aliases). The order of precedence for best match is described above. +.sp +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8), +.BR lstat (2), +.BR selabel_file (5)
diff --git a/selinux/libselinux/man/man3/selabel_lookup_best_match_raw.3 b/selinux/libselinux/man/man3/selabel_lookup_best_match_raw.3 new file mode 100644 index 0000000..8982f17 --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_lookup_best_match_raw.3
@@ -0,0 +1 @@ +.so man3/selabel_lookup_best_match.3
diff --git a/selinux/libselinux/man/man3/selabel_lookup_raw.3 b/selinux/libselinux/man/man3/selabel_lookup_raw.3 new file mode 100644 index 0000000..64e003e --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_lookup_raw.3
@@ -0,0 +1 @@ +.so man3/selabel_lookup.3
diff --git a/selinux/libselinux/man/man3/selabel_open.3 b/selinux/libselinux/man/man3/selabel_open.3 new file mode 100644 index 0000000..971ebc1 --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_open.3
@@ -0,0 +1,108 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_open" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_open, selabel_close \- userspace SELinux labeling interface +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "struct selabel_handle *selabel_open(int " backend , +.in +\w'struct selabel_handle *selabel_open('u +.BI "const struct selinux_opt *" options , +.br +.BI "unsigned " nopt ");" +.in +.sp +.BI "void selabel_close(struct selabel_handle *" hnd ");" +. +.SH "DESCRIPTION" +.BR selabel_open () +is used to initialize a labeling handle to be used for lookup operations. The +.I backend +argument specifies which backend is to be opened; the list of current backends appears in +.B BACKENDS +below. + +The +.I options +argument should be NULL or a pointer to an array of +.B selinux_opt +structures of length +.IR nopt : + +.RS +.ta 4n 16n 24n +.nf +struct selinux_opt { + int type; + const char *value; +}; +.fi +.ta +.RE + +The available option types are described in +.B GLOBAL OPTIONS +below as well as in the documentation for each individual backend. The return value on success is a non-NULL value for use in subsequent label operations. + +.BR selabel_close () +terminates use of a handle, freeing any internal resources associated with it. After this call has been made, the handle must not be used again. +. +.SH "GLOBAL OPTIONS" +Global options which may be passed to +.BR selabel_open () +include the following: +. +.TP +.B SELABEL_OPT_UNUSED +The option with a type code of zero is a no-op. Thus an array of options may be initizalized to zero and any untouched elements will not cause an error. +.TP +.B SELABEL_OPT_VALIDATE +A non-null value for this option enables context validation. By default, +.BR security_check_context (3) +is used; a custom validation function can be provided via +.BR selinux_set_callback (3). +Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation. +.TP +.B SELABEL_OPT_DIGEST +A non-null value for this option enables the generation of an SHA1 digest of +the spec files loaded as described in +.BR selabel_digest (3) +. +.SH "BACKENDS" +.TP +.B SELABEL_CTX_FILE +File contexts backend, described in +.BR selabel_file (5). +.TP +.B SELABEL_CTX_MEDIA +Media contexts backend, described in +.BR selabel_media (5). +.TP +.B SELABEL_CTX_X +X Windows contexts backend, described in +.BR selabel_x (5). +.TP +.B SELABEL_CTX_DB +Database objects contexts backend, described in +.BR selabel_db (5). +. +.SH "RETURN VALUE" +A non-NULL handle value is returned on success. On error, NULL is returned and +.I errno +is set appropriately. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.ad l +.nh +.BR selabel_lookup (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selabel_partial_match.3 b/selinux/libselinux/man/man3/selabel_partial_match.3 new file mode 100644 index 0000000..4cd46f7 --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_partial_match.3
@@ -0,0 +1,34 @@ +.TH "selabel_partial_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selabel_partial_match \- determine whether a direct or partial match is +possible on a file path \- Only supported on file backend. +. +.SH "SYNOPSIS" +.B #include <stdbool.h> +.br +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "bool selabel_partial_match(struct selabel_handle *" hnd , +.in +\w'int selabel_partial_match('u +.BI "const char *" key ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_partial_match () +performs a partial match operation on the handle +.IR hnd , +returning TRUE or FALSE. +The \fIkey\fR parameter is a file path to check for a direct or partial match. +.sp +.SH "RETURN VALUE" +TRUE is returned if a direct or partial match is found, FALSE if not. +.sp +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8), +.BR selabel_file (5)
diff --git a/selinux/libselinux/man/man3/selabel_stats.3 b/selinux/libselinux/man/man3/selabel_stats.3 new file mode 100644 index 0000000..44e1a65 --- /dev/null +++ b/selinux/libselinux/man/man3/selabel_stats.3
@@ -0,0 +1,35 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_stats" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_stats \- obtain SELinux labeling statistics +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.br +.B #include <selinux/label.h> +.sp +.BI "void selabel_stats(struct selabel_handle *" hnd ");" +. +.SH "DESCRIPTION" +.BR selabel_stats () +causes zero or more messages to be printed containing backend-specific information about number of queries performed, number of unused entries, or other operational information. + +The messages are printed to standard error by default; a custom logging function can be provided via +.BR selinux_set_callback (3). +. +.SH "RETURN VALUE" +None. +. +.SH "ERRORS" +None. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_lookup (3), +.BR selinux_set_callback (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selinux_binary_policy_path.3 b/selinux/libselinux/man/man3/selinux_binary_policy_path.3 new file mode 100644 index 0000000..edaa3b8 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_binary_policy_path.3
@@ -0,0 +1,115 @@ +.TH "selinux_binary_policy_path" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API Documentation" +.SH "NAME" +selinux_path, selinux_policy_root, selinux_binary_policy_path, selinux_current_policy_path, +selinux_failsafe_context_path, selinux_removable_context_path, +selinux_default_context_path, selinux_user_contexts_path, +selinux_file_context_path, selinux_media_context_path, +selinux_contexts_path, selinux_booleans_path \- These functions return the paths to the active SELinux policy configuration +directories and files +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp + +.B const char *selinux_path(void); +.sp +.B const char *selinux_policy_root(void); +.sp +.B const char *selinux_binary_policy_path(void); +.sp +.B const char *selinux_current_policy_path(void); +.sp +.B const char *selinux_failsafe_context_path(void); +.sp +.B const char *selinux_removable_context_path(void); +.sp +.B const char *selinux_default_context_path(void); +.sp +.B const char *selinux_user_contexts_path(void); +.sp +.B const char *selinux_usersconf_path(void); +.sp +.B const char *selinux_x_context_path(void); +.sp +.B const char *selinux_sepgsql_context_path(void); +.sp +.B const char *selinux_file_context_path(void); +.sp +.B const char *selinux_media_context_path(void); +.sp +.B const char *selinux_securetty_types_path(void); +.sp +.B const char *selinux_contexts_path(void); +.sp +.B const char *selinux_booleans_path(void); +. +.SH "DESCRIPTION" +These functions return the paths to the active policy configuration +directories and files based on the settings in +.IR /etc/selinux/config . +.sp +.BR selinux_path () +returns the top-level SELinux configuration directory. +.sp +.BR selinux_policy_root () +returns the top-level policy directory. +.sp +.BR selinux_binary_policy_path () +returns the binary policy file loaded into kernel. +.sp +.BR selinux_current_policy_path () +returns the currently loaded policy file from the kernel. +.sp +.BR selinux_default_type_path () +returns the context file mapping roles to default types. +.sp +.BR selinux_failsafe_context_path () +returns the failsafe context for emergency logins. +.sp +.BR selinux_removable_context_path () +returns the filesystem context for removable media. +.sp +.BR selinux_default_context_path () +returns the system-wide default contexts for user sessions. +.sp +.BR selinux_user_contexts_path () +returns the directory containing per-user default contexts. +.sp +.BR selinux_usersconf_path () +returns the file containing mapping between Linux Users and SELinux users. +.sp +.BR selinux_x_context_path () +returns the file containing configuration for XSELinux extension. +.sp +.BR selinux_sepgsql_context_path () +returns the file containing configuration for SE-PostgreSQL. +.sp +.BR selinux_netfilter_context_path () +returns the default netfilter context. +.sp +.BR selinux_file_context_path () +returns the default system file contexts configuration. +.sp +.BR selinux_file_context_local_path () +returns the local customization file contexts configuration. +.sp +.BR selinux_file_context_homedir_path () +returns the home directory file contexts configuration. +.sp +.BR selinux_media_context_path () +returns the file contexts for media device nodes. +.sp +.BR selinux_contexts_path () +returns the directory containing all of the context configuration files. +.sp +.BR selinux_securetty_types_path () +returns the defines tty types for newrole securettys. +.sp +.BR selinux_booleans_path () +returns the initial policy boolean settings. +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_boolean_sub.3 b/selinux/libselinux/man/man3/selinux_boolean_sub.3 new file mode 100644 index 0000000..308c268 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_boolean_sub.3
@@ -0,0 +1,29 @@ +.TH "selinux_boolean_sub" "3" "11 June 2012" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_boolean_sub \- +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "char *selinux_boolean_sub(const char *" boolean_name ");" +.sp +.SH "DESCRIPTION" +.BR selinux_boolean_sub () +searches the +.I \%/etc/selinux/{POLICYTYPE}/booleans.subs_dist +file +for a maching boolean_name record. If the record exists the boolean substitution name is returned. If not +.BR \%selinux_boolean_sub () +returns the original +.IR \%boolean_name . + +.SH "RETURN VALUE" +.BR selinux_boolean_sub () +returns the +.I boolean_name +or the substituted name on success. The returned value must be freed with +.BR free "(3)." +.BR selinux_boolean_sub () +returns NULL on error. +.SH "SEE ALSO" +.BR security_get_boolean_names (3)
diff --git a/selinux/libselinux/man/man3/selinux_booleans_path.3 b/selinux/libselinux/man/man3/selinux_booleans_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_booleans_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_check_access.3 b/selinux/libselinux/man/man3/selinux_check_access.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_check_access.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/selinux_check_passwd_access.3 b/selinux/libselinux/man/man3/selinux_check_passwd_access.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_check_passwd_access.3
@@ -0,0 +1 @@ +.so man3/security_compute_av.3
diff --git a/selinux/libselinux/man/man3/selinux_check_securetty_context.3 b/selinux/libselinux/man/man3/selinux_check_securetty_context.3 new file mode 100644 index 0000000..05f2344 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_check_securetty_context.3
@@ -0,0 +1,16 @@ +.TH "selinux_check_securetty_context" "3" "1 January 2007" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_check_securetty_context \- check whether a SELinux tty security context is defined as a securetty context +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_check_securetty_context(char * "tty_context ); +. +.SH "DESCRIPTION" +.BR selinux_check_securetty_context () +returns 0 if tty_context is a securetty context, +returns < 0 otherwise. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_colors_path.3 b/selinux/libselinux/man/man3/selinux_colors_path.3 new file mode 100644 index 0000000..cc57e43 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_colors_path.3
@@ -0,0 +1,37 @@ +.TH "selinux_colors_path" "3" "08 April 2011" "SELinux API documentation" +.SH "NAME" +selinux_colors_path \- Return a path to the active SELinux policy color configuration file +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.B const char *selinux_colors_path(void); +. +.SH "DESCRIPTION" +.BR selinux_colors_path () +returns the path to the active policy color configuration file. +.sp +The path is built from the path returned by +.BR selinux_policy_root "(3)" +with +.I /secolor.conf +appended. +.sp +This optional configuration file whose format is shown in +.BR \%secolor.conf (5), +controls the colors to be associated with the +.I raw +context components of the +.BR selinux_raw_context_to_color "(3)" +function when information is to be displayed by an SELinux color-aware application. +. +.SH "RETURN VALUE" +On success, the path to the active policy color configuration file is returned. If a path is not available NULL is returned. +. +.SH "ERRORS" +None. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_policy_root "(3), " selinux_config "(5), " selinux_raw_context_to_color "(3), " secolor.conf "(5)"
diff --git a/selinux/libselinux/man/man3/selinux_contexts_path.3 b/selinux/libselinux/man/man3/selinux_contexts_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_contexts_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_current_policy_path.3 b/selinux/libselinux/man/man3/selinux_current_policy_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_current_policy_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_default_context_path.3 b/selinux/libselinux/man/man3/selinux_default_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_default_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_default_type_path.3 b/selinux/libselinux/man/man3/selinux_default_type_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_default_type_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_failsafe_context_path.3 b/selinux/libselinux/man/man3/selinux_failsafe_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_failsafe_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_file_context_cmp.3 b/selinux/libselinux/man/man3/selinux_file_context_cmp.3 new file mode 100644 index 0000000..f7cd7ec --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_file_context_cmp.3
@@ -0,0 +1,74 @@ +.TH "selinux_file_context_cmp" "3" "08 March 2011" "SELinux API documentation" +.SH "NAME" +selinux_file_context_cmp \- Compare two SELinux security contexts excluding the 'user' component +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_file_context_cmp(const char * " a ", " +.RS +.BI "const char * " b ");" +.RE +. +.SH "DESCRIPTION" +.BR selinux_file_context_cmp () +compares two context strings excluding the user component with +.BR strcmp (3) +as shown in the +.B EXAMPLE +section. +.sp +This is useful as for most object contexts, the user component is not relevant. +. +.SH "RETURN VALUE" +The return values follow the +.BR strcmp (3) +function, where: +.RS +0 if they are equal. +.RE +.RS +1 if +.I a +is greater than +.I b +.RE +.RS +\-1 if +.I a +is less than +.I b +.RE +. +.SH "ERRORS" +None. +. +.SH "NOTES" +The contexts being compared do not specifically need to be file contexts. +. +.SH "EXAMPLE" +If context +.I a +is: +.RS +user_u:user_r:user_t:s0 +.RE +.sp +and context +.I b +is: +.RS +root:user_r:user_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:user_r:user_t:s0 and :user_r:user_t:s0 +.RE +.sp +Therefore they will match and +.BR selinux_file_context_cmp () +will return zero. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_file_context_homedir_path.3 b/selinux/libselinux/man/man3/selinux_file_context_homedir_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_file_context_homedir_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_file_context_local_path.3 b/selinux/libselinux/man/man3/selinux_file_context_local_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_file_context_local_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_file_context_path.3 b/selinux/libselinux/man/man3/selinux_file_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_file_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_file_context_verify.3 b/selinux/libselinux/man/man3/selinux_file_context_verify.3 new file mode 100644 index 0000000..893949f --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_file_context_verify.3
@@ -0,0 +1,101 @@ +.TH "selinux_file_context_verify" "3" "08 March 2011" "SELinux API documentation" +.SH "NAME" +selinux_file_context_verify \- Compare the SELinux security context on disk to the default security context required by the policy file contexts file +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");" +. +.SH "DESCRIPTION" +.BR selinux_file_context_verify () +compares the context of the specified +.I path +that is held on disk (in the extended attribute), to the system default entry held in the file contexts series of files. +.sp +The +.I mode +may be zero. +.sp +Note that the two contexts are compared for "significant" differences (i.e. the user component of the contexts are ignored) as shown in the +.B EXAMPLE +section. +. +.SH "RETURN VALUE" +If the contexts significantly match, 1 (one) is returned. +.sp +If the contexts do not match 0 (zero) is returned and +.I errno +is set to either +.B ENOENT +or +.B EINVAL +for the reasons listed in the +.B ERRORS +section, or if +.I errno += 0 then the contexts did not match. +.sp +On failure \-1 is returned and +.I errno +set appropriately. +. +.SH "ERRORS" +.TP +.B ENOTSUP +if extended attributes are not supported by the file system. +.TP +.B ENOENT +if there is no entry in the file contexts series of files or +.I path +does not exist. +.TP +.B EINVAL +if the entry in the file contexts series of files or +.I path +are invalid, or the returned context fails validation. +.TP +.B ENOMEM +if attempt to allocate memory failed. +. +.SH "FILES" +The following configuration files (the file contexts series of files) supporting the active policy will be used (should they exist) to determine the +.I path +default context: +.sp +.RS +.I contexts/files/file_contexts +- This file must exist. +.sp +.I contexts/files/file_contexts.local +- If exists has local customizations. +.sp +.I contexts/files/file_contexts.homedirs +- If exists has users home directory customizations. +.sp +.I contexts/files/file_contexts.subs +- If exists has substitutions that are then applied to the 'in memory' version of the file contexts files. +.RE +. +.SH "EXAMPLE" +If the files context is: +.RS +unconfined_u:object_r:admin_home_t:s0 +.RE +.sp +and the default context defined in the file contexts file is: +.RS +system_u:object_r:admin_home_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:object_r:admin_home_t:s0 and :object_r:admin_home_t:s0 +.RE +.sp +Therefore they will match and +.BR selinux_file_context_verify () +will return 1. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_getenforcemode.3 b/selinux/libselinux/man/man3/selinux_getenforcemode.3 new file mode 100644 index 0000000..7ed94c1 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_getenforcemode.3
@@ -0,0 +1,31 @@ +.TH "selinux_getenforcemode" "3" "25 May 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_getenforcemode \- get the enforcing state of SELinux +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_getenforcemode(int *" enforce ); +. +.SH "DESCRIPTION" +.BR selinux_getenforcemode () +Reads the contents of the +.I /etc/selinux/config +file to determine how the system was setup to run SELinux. + +Sets the value of +.I enforce +to 1 if SELinux should be run in enforcing mode. +Sets the value of +.I enforce +to 0 if SELinux should be run in permissive mode. +Sets the value of +.I enforce +to \-1 if SELinux should be disabled. +. +.SH "RETURN VALUE" +On success, zero is returned. +On failure, \-1 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_getpolicytype.3 b/selinux/libselinux/man/man3/selinux_getpolicytype.3 new file mode 100644 index 0000000..c947e2c --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_getpolicytype.3
@@ -0,0 +1,23 @@ +.TH "selinux_getpolicytype" "3" "24 Sep 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_getpolicytype \- get the type of SELinux policy running on the system +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_getpolicytype(char **" policytype ); +. +.SH "DESCRIPTION" +.BR selinux_getpolicytype () +Reads the contents of the +.I /etc/selinux/config +file to determine the SELinux policy used on the system, and sets +.I \%policytype +accordinly. +. +.SH "RETURN VALUE" +On success, zero is returned. +On failure, \-1 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_homedir_context_path.3 b/selinux/libselinux/man/man3/selinux_homedir_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_homedir_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_init_load_policy.3 b/selinux/libselinux/man/man3/selinux_init_load_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_init_load_policy.3
@@ -0,0 +1 @@ +.so man3/security_load_policy.3
diff --git a/selinux/libselinux/man/man3/selinux_lsetfilecon_default.3 b/selinux/libselinux/man/man3/selinux_lsetfilecon_default.3 new file mode 100644 index 0000000..d4fc658 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_lsetfilecon_default.3
@@ -0,0 +1,20 @@ +.TH "selinux_lsetfilecon_default" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +selinux_lsetfilecon_default \- set the file context to the system defaults +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_lsetfilecon_default(const char *" path ");" +. +.SH "DESCRIPTION" +.BR selinux_lsetfilecon_default () +sets the file context to the system defaults. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_file_context_cmp "(3), " selinux_file_context_verify "(3), " matchpathcon "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/selinux_media_context_path.3 b/selinux/libselinux/man/man3/selinux_media_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_media_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_mkload_policy.3 b/selinux/libselinux/man/man3/selinux_mkload_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_mkload_policy.3
@@ -0,0 +1 @@ +.so man3/security_load_policy.3
diff --git a/selinux/libselinux/man/man3/selinux_netfilter_context_path.3 b/selinux/libselinux/man/man3/selinux_netfilter_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_netfilter_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_path.3 b/selinux/libselinux/man/man3/selinux_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_policy_root.3 b/selinux/libselinux/man/man3/selinux_policy_root.3 new file mode 100644 index 0000000..63dc901 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_policy_root.3
@@ -0,0 +1,34 @@ +.TH "selinux_policy_root" "3" "25 May 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_policy_root \- return the path of the SELinux policy files for this machine +selinux_set_policy_root \- Set an alternate SELinux root path for the SELinux policy files for this machine. +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.B const char *selinux_policy_root(void); +. +.sp +.B int selinux_set_policy_root(const char *policypath); +. +.SH "DESCRIPTION" +.BR selinux_policy_root () +reads the contents of the +.I /etc/selinux/config +file to determine which policy files should be used for this machine. +. +.BR selinux_set_policy_root () +sets up all all policy paths based on the alternate root + +.I /etc/selinux/config +file to determine which policy files should be used for this machine. +. +.SH "RETURN VALUE" +On success, selinux_policy_root returns a directory path containing the SELinux policy files. +On failure, selinux_policy_root returns NULL. + +On success, selinux_set_policy_root returns 0 on success -1 on failure. + +. +.SH "SEE ALSO" +.BR selinux "(8)"
diff --git a/selinux/libselinux/man/man3/selinux_raw_context_to_color.3 b/selinux/libselinux/man/man3/selinux_raw_context_to_color.3 new file mode 100644 index 0000000..530e876 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_raw_context_to_color.3
@@ -0,0 +1,123 @@ +.TH "selinux_raw_context_to_color" "3" "08 April 2011" "SELinux API documentation" +.SH "NAME" +selinux_raw_context_to_color \- Return RGB color string for an SELinux security context +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int selinux_raw_context_to_color(char * " raw ", " +.RS +.BI "char **" color_str ");" +.RE +. +.SH "DESCRIPTION" +.BR selinux_raw_context_to_color () +returns a +.I color_str +associated to the raw context +.I raw +provided that the +.BR mcstransd "(8)" +daemon is running, the policy is an MLS type policy (MCS or MLS) and there is a color configuration file +.BR \%secolor.conf (5) +(see the +.B FILES +section). +.sp +The +.I color_str +string is a space separated list of eight hexadecimal RGB triples, each prefixed by a hash character (#). These represent the user:role:type:range components of the foreground and background colors. An example string is shown in the +.B EXAMPLE +section. + +The returned +.I color_str +string must be freed with +.BR free "(3)." + +If a color has not been configured for a specific user, role, type and/or range component of context +.IR raw "," +then +.BR \%selinux_raw_context_to_color () +will select the color returned in +.I color_str +in order of precedence as follows: +.RS +role, type, range +.br +user, type, range +.br +user, role, range +.br +user, role, type +.br +.RE + +If there are no entries in the +.BR secolor.conf (5) +file for any of the components of context +.I raw +(or the file is not present), then the default string returned in +.I color_str +is: +.sp +.RS +----- user ---- ---- role ---- ---- type ---- ---- range ---- +.br +#000000 #ffffff #000000 #ffffff #000000 #ffffff #000000 #ffffff +.sp +.RE +. +.SH "RETURN VALUE" +On success, zero is returned. +.br +On failure, \-1 is returned with +.I errno +set appropriately. +. +.SH "ERRORS" +.B ENOENT +If the +.BR mcstransd "(8)" +daemon is not running. +. +.SH "FILES" +.BR selinux_raw_context_to_color () +obtains the translated entry from the active policy +.BR secolor.conf "(5)" +file as returned by +.BR \%selinux_colors_path (3). +The file format is described in +.BR \%secolor.conf (5). +. +.SH "NOTES" +1. The primary use of +.BR selinux_raw_context_to_color () +is to return a color that corresponds to a range, that can then be used to highlight information at different MLS levels. +.sp +2. The +.BR mcstransd "(8)" +daemon process security level must dominate the +.I raw +security level passed to it by the +.BR selinux_raw_context_to_color () +function. If not, the range color selected will be as defined by the order of precedence. +. +.SH "EXAMPLE" +.BR selinux_raw_context_to_color () +returns the foreground and background colors of the context string components (user:role:type:range) as RGB triples as follows: +.sp + + user : role : type : range +.br + fg bg : fg bg : fg bg : fg bg +.br +#000000 #ffffff #ffffff #000000 #d2b48c #ffa500 #000000 #008000 +.br + black white : white black : tan orange : black green +.br +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_colors_path "(3), " mcstransd "(8), " secolor.conf "(5), " selinux_raw_to_trans_context "(3), " selinux_trans_to_raw_context "(3), " free "(3)"
diff --git a/selinux/libselinux/man/man3/selinux_removable_context_path.3 b/selinux/libselinux/man/man3/selinux_removable_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_removable_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_restorecon.3 b/selinux/libselinux/man/man3/selinux_restorecon.3 new file mode 100644 index 0000000..0293c4d --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_restorecon.3
@@ -0,0 +1,203 @@ +.TH "selinux_restorecon" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon \- restore file(s) default SELinux security contexts +. +.SH "SYNOPSIS" +.B #include <selinux/restorecon.h> +.sp +.BI "int selinux_restorecon(const char *" pathname , +.in +\w'int selinux_restorecon('u +.br +.BI "unsigned int " restorecon_flags ");" +.in +. +.SH "DESCRIPTION" +.BR selinux_restorecon () +restores file default security contexts on filesystems that support extended +attributes (see +.BR xattr (7)), +based on: +.sp +.RS +.IR pathname +containing a directory or file to be relabeled. +.br +If this is a directory and the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +has been set (for decending through directories), then +.BR selinux_restorecon () +will write an SHA1 digest of the combined specfiles (see the +.B NOTES +section for details) to an extended attribute of +.IR security.restorecon_last +once the relabeling has been completed successfully. This digest will be +checked should +.BR selinux_restorecon () +be rerun +with the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +flag set. If any of the specfiles had been updated, the digest +will also be updated. However if the digest is the same, no relabeling checks +will take place (unless the +.B SELINUX_RESTORECON_IGNORE_DIGEST +flag is set). +.sp +.IR restorecon_flags +contains the labeling option/rules as follows: +.sp +.RS +.sp +.B SELINUX_RESTORECON_IGNORE_DIGEST +force the checking of labels even if the stored SHA1 digest matches the +specfiles SHA1 digest. The specfiles digest will be written to the +.IR security.restorecon_last +extended attribute once relabeling has been completed successfully provided the +.B SELINUX_RESTORECON_NOCHANGE +flag has not been set. +.sp +.B SELINUX_RESTORECON_NOCHANGE +don't change any file labels (passive check) or update the digest in the +.IR security.restorecon_last +extended attribute. +.sp +.B SELINUX_RESTORECON_SET_SPECFILE_CTX +If set, reset the files label to match the default specfile context. +If not set only reset the files "type" component of the context to match the +default specfile context. +.br + +.sp +.B SELINUX_RESTORECON_RECURSE +change file and directory labels recursively (descend directories) +and if successful write an SHA1 digest of the combined specfiles to an +extended attribute as described in the +.B NOTES +section. +.sp +.B SELINUX_RESTORECON_VERBOSE +log file label changes. +.RS +Note that if +.B SELINUX_RESTORECON_VERBOSE +and +.B SELINUX_RESTORECON_PROGRESS +are set, then +.B SELINUX_RESTORECON_PROGRESS +will take precedence. +.RE +.sp +.B SELINUX_RESTORECON_PROGRESS +show progress by printing * to stdout every 1000 files. +.sp +.B SELINUX_RESTORECON_REALPATH +convert passed-in +.I pathname +to the canonical pathname using +.BR realpath (3). +.sp +.B SELINUX_RESTORECON_XDEV +prevent descending into directories that have a different device number than +the +.I pathname +entry from which the descent began. +.RE +.sp +The behavior regarding the checking and updating of the SHA1 digest described +above is the default behavior. It is possible to change this by first calling +.BR selabel_open (3) +and not enabling the +.B SELABEL_OPT_DIGEST +option, then calling +.BR selinux_restorecon_set_sehandle (3) +to set the handle to be used by +.BR selinux_restorecon (3). +.sp +If the +.I pathname +is a directory path, then it is possible to set files/directories to be +excluded from the path by calling +.BR selinux_restorecon_set_exclude_list (3) +with a +.B NULL +terminated list before calling +.BR selinux_restorecon (3). +.RE +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "NOTES" +To improve performance when relabeling file systems recursively (e.g. the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +flag is set) +.BR selinux_restorecon () +will write an SHA1 digest of the specfiles that are processed by +.BR selabel_open (3) +to an extended attribute named +.IR security.restorecon_last +to the directory specified in the +.IR pathname . +.sp +To check the extended attribute entry use +.BR getfattr (1) , +for example: +.sp +.RS +getfattr -e hex -n security.restorecon_last / +.RE +.sp +The SHA1 digest is calculated by +.BR selabel_open (3) +concatenating the specfiles it reads during initialisation with the +resulting digest and list of specfiles being retrieved by +.BR selabel_digest (3). +.sp +The specfiles consist of the mandatory +.I file_contexts +file plus any subs, subs_dist, local and homedir entries (text or binary versions) +as determined by any +.BR selabel_open (3) +options e.g. +.BR SELABEL_OPT_BASEONLY . +.sp +Should any of the specfiles have changed, then when +.BR selinux_restorecon () +is run again with the +.B SELINUX_RESTORECON_RECURSE +flag set, a new SHA1 digest will be calculated and all files will be automatically +relabeled depending on the settings of the +.B SELINUX_RESTORECON_SET_SPECFILE_CTX +flag (provided +.B SELINUX_RESTORECON_NOCHANGE +is not set). +.sp +.B /sys +and in-memory filesystems do not support the +.IR security.restorecon_last +extended attribute and are automatically excluded from any relabeling checks. +.sp +.BR selinux_restorecon () +does not check whether mounted filesystems support the +.B seclabel +option (i.e. support extended attributes as described in +.BR xattr (7)). +To exclude these filesystems from any relabeling checks +.BR selinux_restorecon_set_exclude_list (3) +should be called prior to +.BR selinux_restorecon () +with a NULL terminated +.IR exclude_list +of these filesystems. +. +.SH "SEE ALSO" +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_exclude_list (3),
diff --git a/selinux/libselinux/man/man3/selinux_restorecon_default_handle.3 b/selinux/libselinux/man/man3/selinux_restorecon_default_handle.3 new file mode 100644 index 0000000..0f1e737 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_restorecon_default_handle.3
@@ -0,0 +1,59 @@ +.TH "selinux_restorecon_default_handle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_default_handle \- sets default parameters for +.BR selinux_restorecon (3) +. +.SH "SYNOPSIS" +.B #include <selinux/restorecon.h> +.br +.B #include <selinux/label.h> +.sp +.B "struct selabel_handle *selinux_restorecon_default_handle(void);" +. +.SH "DESCRIPTION" +.BR selinux_restorecon_default_handle () +sets default parameters for +.BR selinux_restorecon (3) +by calling +.BR selabel_open (3) +with the +.B SELABEL_OPT_DIGEST +option only. This will enable a digest to be calculated on the currently +loaded policy +.BR file_contexts (5) +set of files as described in the +.B NOTES +section of +.BR selinux_restorecon (3). +.sp +Calling +.BR selinux_restorecon_default_handle () +is optional, however if used then +.BR selinux_restorecon_set_sehandle (3) +should be called with the returned handle to set this for use by +.BR selinux_restorecon (3). +.sp +.BR selinux_restorecon_default_handle () +is optional as +.BR selinux_restorecon (3) +will automatically call this and +.BR selinux_restorecon_set_sehandle (3) +provided a handle has not already been set, for +example by +.BR selinux_restorecon_set_sehandle (3) +to set customised +.BR selabel_open (3) +parameters. +. +.SH "RETURN VALUE" +A non\-NULL handle value is returned on success. On error, NULL is returned and +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_set_exclude_list (3)
diff --git a/selinux/libselinux/man/man3/selinux_restorecon_set_exclude_list.3 b/selinux/libselinux/man/man3/selinux_restorecon_set_exclude_list.3 new file mode 100644 index 0000000..ea1fb78 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_restorecon_set_exclude_list.3
@@ -0,0 +1,32 @@ +.TH "selinux_restorecon_set_exclude_list" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_set_exclude_list \- set list of files/directories to be +excluded from relabeling. +. +.SH "SYNOPSIS" +.B #include <selinux/restorecon.h> +.sp +.BI "void selinux_restorecon_set_exclude_list(const char **" exclude_list ");" +.in +\w'void selinux_restorecon_set_exclude_list('u +. +.SH "DESCRIPTION" +.BR selinux_restorecon_set_exclude_list () +passes to +.BR selinux_restorecon (3) +a pointer containing a +.B NULL +terminated list of one or more directories or files that are not to be +relabeled in +.IR exclude_list . +.sp +.BR selinux_restorecon_set_exclude_list () +must be called prior to +.BR selinux_restorecon (3). +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3)
diff --git a/selinux/libselinux/man/man3/selinux_restorecon_set_sehandle.3 b/selinux/libselinux/man/man3/selinux_restorecon_set_sehandle.3 new file mode 100644 index 0000000..6182f54 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_restorecon_set_sehandle.3
@@ -0,0 +1,39 @@ +.TH "selinux_restorecon_set_sehandle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_set_sehandle \- set a labeling handle for use by +.BR selinux_restorecon (3) +. +.SH "SYNOPSIS" +.B #include <selinux/restorecon.h> +.br +.B #include <selinux/label.h> +.sp +.BI "void selinux_restorecon_set_sehandle(struct selabel_handle *" handle ");" +.in +\w'void selinux_restorecon_set_sehandle('u +. +.SH "DESCRIPTION" +.BR selinux_restorecon_set_sehandle () +sets the +.I handle +to be use by +.BR selinux_restorecon (3) +when relabeling files. +.sp +.BR selinux_restorecon_set_sehandle () +is generally used when customised +.BR selabel_open (3) +parameters are required to perform relabeling operations with +.BR selinux_restorecon (3). +.sp +.BR selinux_restorecon_set_sehandle () +will output to the default SELinux log information regarding whether a digest +is available or not. If it were available, the message will contain the SHA1 +digest and a list of specfiles used to compute the digest. +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_default_handle (3)
diff --git a/selinux/libselinux/man/man3/selinux_securetty_types_path.3 b/selinux/libselinux/man/man3/selinux_securetty_types_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_securetty_types_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_set_callback.3 b/selinux/libselinux/man/man3/selinux_set_callback.3 new file mode 100644 index 0000000..a4c613a --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_set_callback.3
@@ -0,0 +1,118 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selinux_set_callback" "3" "20 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selinux_set_callback \- userspace SELinux callback facilities +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "void selinux_set_callback(int " type ", union selinux_callback " callback ");" +. +.SH "DESCRIPTION" +.BR selinux_set_callback () +sets the callback indicated by +.I type +to the value of +.IR callback , +which should be passed as a function pointer cast to type +.B union +.BR selinux_callback . + +All callback functions should return a negative value with +.I errno +set appropriately on error. + +The available values for +.I type +are: +.TP +.B SELINUX_CB_LOG +.BI "int (*" func_log ") (int " type ", const char *" fmt ", ...);" + +This callback is used for logging and should process the +.BR printf (3) +style +.I fmt +string and arguments as appropriate. The +.I type +argument indicates the type of message and will be set to one of the following: + +.B SELINUX_ERROR + +.B SELINUX_WARNING + +.B SELINUX_INFO + +.B SELINUX_AVC +. +.TP +.B SELINUX_CB_AUDIT +.BI "int (*" func_audit ") (void *" auditdata ", security_class_t " cls , +.in +\w'int (*func_audit) ('u +.BI "char *" msgbuf ", size_t " msgbufsize ");" +.in + +This callback is used for supplemental auditing in AVC messages. The +.I auditdata +and +.I cls +arguments are the values passed to +.BR avc_has_perm (3). +A human-readable interpretation should be printed to +.I msgbuf +using no more than +.I msgbufsize +characters. +. +.TP +.B SELINUX_CB_VALIDATE +.BI "int (*" func_validate ") (char **" ctx ");" + +This callback is used for context validation. The callback may optionally modify the input context by setting the target of the +.I ctx +pointer to a new context. In this case, the old value should be freed with +.BR freecon (3). +The value of +.I errno +should be set to +.B EINVAL +to indicate an invalid context. +. +.TP +.B SELINUX_CB_SETENFORCE +.BI "int (*" func_setenforce ") (int " enforcing ");" + +This callback is invoked when the system enforcing state changes. +The +.I enforcing +argument indicates the new value and is set to +.I 1 +for enforcing mode, and +.I 0 +for permissive mode. +. +.TP +.B SELINUX_CB_POLICYLOAD +.BI "int (*" func_policyload ") (int " seqno ");" + +This callback is invoked when the system security policy is reloaded. +The +.I seqno +argument is the current sequential number of the policy generation in the system. +. +.SH "RETURN VALUE" +None. +. +.SH "ERRORS" +None. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR avc_init (3), +.BR avc_netlink_open (3), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selinux_set_mapping.3 b/selinux/libselinux/man/man3/selinux_set_mapping.3 new file mode 100644 index 0000000..a93f7b2 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_set_mapping.3
@@ -0,0 +1,88 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2008 +.TH "selinux_set_mapping" "3" "12 Jun 2008" "" "SELinux API documentation" +.SH "NAME" +selinux_set_mapping \- establish dynamic object class and permission mapping +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.nf +struct security_class_mapping { + const char *name; + const char *perms[]; +}; +.fi +.sp +.BI "int selinux_set_mapping(struct security_class_mapping *" map ");" +. +.SH "DESCRIPTION" +.BR selinux_set_mapping () +establishes a mapping from a user-provided ordering of object classes and permissions to the numbers actually used by the loaded system policy. Use of this function is highly preferred over the generated constants in the libselinux header files, as this method allows the policy's class and permission values to change over time. + +After the mapping is established, all libselinux functions that operate on class and permission values take the user-provided numbers, which are determined as follows: + +The +.I map +argument consists of an array of +.B security_class_mapping +structures, which must be terminated by a structure having a NULL name field. Except for this last structure, the +.I name +field should refer to the string name of an object class, and the corresponding +.I perms +field should refer to an array of permission bit names terminated by a NULL string. + +The object classes named in the mapping and the bit indexes of each set of permission bits named in the mapping are numbered in order starting from 1. These numbers are the values that should be passed to subsequent libselinux calls. +. +.SH "RETURN VALUE" +Zero is returned on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +One of the class or permission names requested in the mapping is not present in the loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "EXAMPLE" +.RS +.ta 4n 10n +.nf +struct security_class_mapping map[] = { + { "file", { "create", "unlink", "read", "write", NULL } }, + { "socket", { "bind", NULL } }, + { "process", { "signal", NULL } }, + { NULL } +}; + +if (selinux_set_mapping(map) < 0) + exit(1); +.fi +.ta +.RE + +In this example, after the call has succeeded, classes +.BR file , +.BR socket , +and +.B process +will be identified by 1, 2 and 3, respectively. Permissions +.IR create , +.IR unlink , +.IR read , +and +.I write +(for the +.B file +class) will be identified by 1, 2, 4, and 8 respectively. Classes and permissions not listed in the mapping cannot be used. +. +.SH "AUTHOR" +Eamon Walsh <ewalsh@tycho.nsa.gov> +. +.SH "SEE ALSO" +.BR avc_open (8), +.BR selinux (8)
diff --git a/selinux/libselinux/man/man3/selinux_set_policy_root.3 b/selinux/libselinux/man/man3/selinux_set_policy_root.3 new file mode 100644 index 0000000..8077658 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_set_policy_root.3
@@ -0,0 +1 @@ +.so man3/selinux_policy_root.3
diff --git a/selinux/libselinux/man/man3/selinux_status_close.3 b/selinux/libselinux/man/man3/selinux_status_close.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_close.3
@@ -0,0 +1 @@ +.so man3/selinux_status_open.3
diff --git a/selinux/libselinux/man/man3/selinux_status_deny_unknown.3 b/selinux/libselinux/man/man3/selinux_status_deny_unknown.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_deny_unknown.3
@@ -0,0 +1 @@ +.so man3/selinux_status_open.3
diff --git a/selinux/libselinux/man/man3/selinux_status_getenforce.3 b/selinux/libselinux/man/man3/selinux_status_getenforce.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_getenforce.3
@@ -0,0 +1 @@ +.so man3/selinux_status_open.3
diff --git a/selinux/libselinux/man/man3/selinux_status_open.3 b/selinux/libselinux/man/man3/selinux_status_open.3 new file mode 100644 index 0000000..2d44be5 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_open.3
@@ -0,0 +1,100 @@ +.TH "selinux_status_open" "3" "22 January 2011" "kaigai@ak.jp.nec.com" "SELinux API documentation" +.SH "NAME" +selinux_status_open, selinux_status_close, selinux_status_updated, +selinux_status_getenforce, selinux_status_policyload and +selinux_status_deny_unknown \- reference the SELinux kernel status +without invocation of system calls +. +.SH "SYNOPSIS" +.B #include <selinux/avc.h> +.sp +.BI "int selinux_status_open(int " fallback ");" +.sp +.BI "void selinux_status_close(void);" +.sp +.BI "int selinux_status_updated(void);" +.sp +.BI "int selinux_status_getenforce(void);" +.sp +.BI "int selinux_status_policyload(void);" +.sp +.BI "int selinux_status_deny_unknown(void);" +. +.SH "DESCRIPTION" +Linux 2.6.37 or later provides a SELinux kernel status page; being mostly +placed on +.I /sys/fs/selinux/status +entry. It enables userspace applications to mmap this page with read-only +mode, then it informs some status without system call invocations. +.sp +In some cases that a userspace application tries to apply heavy frequent +access control; such as row-level security in databases, it will face +unignorable cost to communicate with kernel space to check invalidation +of userspace avc. +.sp +These functions provides applications a way to know some kernel events +without system-call invocation or worker thread for monitoring. +.sp +.BR selinux_status_open () +tries to +.BR open (2) +.I /sys/fs/selinux/status +and +.BR mmap (2) +it in read-only mode. The file-descriptor and pointer to the page shall +be stored internally; Don't touch them directly. +Set 1 on the +.I fallback +argument to handle a case of older kernels without kernel status page support. +In this case, this function tries to open a netlink socket using +.BR avc_netlink_open (3) +and overwrite corresponding callbacks ( setenforce and policyload). +Thus, we need to pay attention to the interaction with these interfaces, +when fallback mode is enabled. +.sp +.BR selinux_status_close () +unmap the kernel status page and close its file descriptor, or close the +netlink socket if fallbacked. +.sp +.BR selinux_status_updated () +informs us whether something has been updated since the last call. +It returns 0 if nothing was happened, however, 1 if something has been +updated in this duration, or \-1 on error. +.sp +.BR selinux_status_getenforce () +returns 0 if SELinux is running in permissive mode, 1 if enforcing mode, +or \-1 on error. +Same as +.BR security_getenforce (3) +except with or without system call invocation. +.sp +.BR selinux_status_policyload () +returns times of policy reloaded on the running system, or \-1 on error. +Note that it is not a reliable value on fallback-mode until it receive +the first event message via netlink socket. +Thus, don't use this value to know actual times of policy reloaded. +.sp +.BR selinux_status_deny_unknown () +returns 0 if SELinux treats policy queries on undefined object classes or +permissions as being allowed, 1 if such queries are denied, or \-1 on error. +.sp +Also note that these interfaces are not thread-safe, so you have to protect +them from concurrent calls using exclusive locks when multiple threads are +performing. +. +.SH "RETURN VALUE" +.BR selinux_status_open () +returns 0 or 1 on success. 1 means we are ready to use these interfaces, +but netlink socket was opened as fallback instead of the kernel status page. +On error, \-1 shall be returned. +.sp +Any other functions with a return value shall return its characteristic +value as described above, or \-1 on errors. +. +.SH "SEE ALSO" +.ad l +.nh +.BR mmap (2), +.BR avc_netlink_open (3), +.BR security_getenforce (3), +.BR security_deny_unknown (3)
diff --git a/selinux/libselinux/man/man3/selinux_status_policyload.3 b/selinux/libselinux/man/man3/selinux_status_policyload.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_policyload.3
@@ -0,0 +1 @@ +.so man3/selinux_status_open.3
diff --git a/selinux/libselinux/man/man3/selinux_status_updated.3 b/selinux/libselinux/man/man3/selinux_status_updated.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_status_updated.3
@@ -0,0 +1 @@ +.so man3/selinux_status_open.3
diff --git a/selinux/libselinux/man/man3/selinux_user_contexts_path.3 b/selinux/libselinux/man/man3/selinux_user_contexts_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_user_contexts_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_usersconf_path.3 b/selinux/libselinux/man/man3/selinux_usersconf_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_usersconf_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/selinux_x_context_path.3 b/selinux/libselinux/man/man3/selinux_x_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/selinux/libselinux/man/man3/selinux_x_context_path.3
@@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3
diff --git a/selinux/libselinux/man/man3/set_matchpathcon_flags.3 b/selinux/libselinux/man/man3/set_matchpathcon_flags.3 new file mode 100644 index 0000000..2841bec --- /dev/null +++ b/selinux/libselinux/man/man3/set_matchpathcon_flags.3
@@ -0,0 +1,62 @@ +.TH "set_matchpathcon_flags" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +set_matchpathcon_flags, set_matchpathcon_invalidcon, set_matchpathcon_printf \- set flags controlling the operation of matchpathcon or matchpathcon_index and configure the behaviour of validity checking and error displaying +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "void set_matchpathcon_flags(unsigned int " flags ");" +.sp +.BI "void set_matchpathcon_invalidcon(int (*" f ")(const char *" path ", unsigned " lineno ", char *" context "));" +.sp +.BI "void set_matchpathcon_printf(void (*" f ")(const char *" fmt ", ...));" +. +.SH "DESCRIPTION" +.BR set_matchpathcon_flags () +sets the flags controlling the operation of +.BR matchpathcon_init (3) +and subsequently +.BR matchpathcon_index (3) +or +.BR matchpathcon (3). +If the +.B MATCHPATHCON_BASEONLY +flag is set, then only the base file contexts configuration file +will be processed, not any dynamically generated entries or local customizations. +.sp + +.BR set_matchpathcon_invalidcon () +sets the function used by +.BR matchpathcon_init (3) +when checking the validity of a context in the file contexts +configuration. If not set, then this defaults to a test based +on +.BR security_check_context (3), +which checks validity against the active policy on a SELinux system. +This can be set to instead perform checking based on a binary policy file, +e.g. using +.BR sepol_check_context (3), +as is done by +.B setfiles \-c. +The function is also responsible for reporting any such error, and +may include the +.I path +and +.I lineno +in such error messages. +.sp + +.BR set_matchpathcon_printf () +sets the function used by +.BR matchpathcon_init (3) +when displaying errors about the file contexts configuration. If not set, +then this defaults to fprintf(stderr, fmt, ...). This can be set to redirect +error reporting to a different destination. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " matchpathcon "(3), " matchpathcon_index "(3), " set_matchpathcon_invalidcon "(3), " set_matchpathcon_printf "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/set_matchpathcon_invalidcon.3 b/selinux/libselinux/man/man3/set_matchpathcon_invalidcon.3 new file mode 100644 index 0000000..b861e1c --- /dev/null +++ b/selinux/libselinux/man/man3/set_matchpathcon_invalidcon.3
@@ -0,0 +1 @@ +.so man3/set_matchpathcon_flags.3
diff --git a/selinux/libselinux/man/man3/set_matchpathcon_printf.3 b/selinux/libselinux/man/man3/set_matchpathcon_printf.3 new file mode 100644 index 0000000..b861e1c --- /dev/null +++ b/selinux/libselinux/man/man3/set_matchpathcon_printf.3
@@ -0,0 +1 @@ +.so man3/set_matchpathcon_flags.3
diff --git a/selinux/libselinux/man/man3/set_selinuxmnt.3 b/selinux/libselinux/man/man3/set_selinuxmnt.3 new file mode 100644 index 0000000..d7805c9 --- /dev/null +++ b/selinux/libselinux/man/man3/set_selinuxmnt.3
@@ -0,0 +1 @@ +.so man3/init_selinuxmnt.3
diff --git a/selinux/libselinux/man/man3/setcon.3 b/selinux/libselinux/man/man3/setcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/setcon.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/setcon_raw.3 b/selinux/libselinux/man/man3/setcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/selinux/libselinux/man/man3/setcon_raw.3
@@ -0,0 +1 @@ +.so man3/getcon.3
diff --git a/selinux/libselinux/man/man3/setexeccon.3 b/selinux/libselinux/man/man3/setexeccon.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/selinux/libselinux/man/man3/setexeccon.3
@@ -0,0 +1 @@ +.so man3/getexeccon.3
diff --git a/selinux/libselinux/man/man3/setexeccon_raw.3 b/selinux/libselinux/man/man3/setexeccon_raw.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/selinux/libselinux/man/man3/setexeccon_raw.3
@@ -0,0 +1 @@ +.so man3/getexeccon.3
diff --git a/selinux/libselinux/man/man3/setfilecon.3 b/selinux/libselinux/man/man3/setfilecon.3 new file mode 100644 index 0000000..9fe8997 --- /dev/null +++ b/selinux/libselinux/man/man3/setfilecon.3
@@ -0,0 +1,66 @@ +.TH "setfilecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +setfilecon, fsetfilecon, lsetfilecon \- set SELinux security context of a file +. +.SH "SYNOPSIS" +.B #include <selinux/selinux.h> +.sp +.BI "int setfilecon(const char *" path ", char * "con ); +.sp +.BI "int setfilecon_raw(const char *" path ", char * "con ); +.sp +.BI "int lsetfilecon(const char *" path ", char * "con ); +.sp +.BI "int lsetfilecon_raw(const char *" path ", char * "con ); +.sp +.BI "int fsetfilecon(int "fd ", char * "con ); +.sp +.BI "int fsetfilecon_raw(int "fd ", char * "con ); +. +.SH "DESCRIPTION" +.BR setfilecon () +sets the security context of the file system object. + +.BR lsetfilecon () +is identical to setfilecon, except in the case of a symbolic link, where the +link itself has it's context set, not the file that it refers to. + +.BR fsetfilecon () +is identical to setfilecon, only the open file pointed to by filedes (as +returned by +.BR open (2)) +has it's context set in place of path. + +.BR setfilecon_raw (), +.BR lsetfilecon_raw (), +and +.BR fsetfilecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On failure, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +If there is insufficient space remaining to store the extended +attribute, +.I errno +is set to either +.BR ENOSPC , +or +.B EDQUOT +if quota enforcement was the cause. + +If extended attributes are not supported by the filesystem, or are disabled, +.I errno +is set to +.BR ENOTSUP . + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(3), " freecon "(3), " getfilecon "(3), " setfscreatecon "(3)"
diff --git a/selinux/libselinux/man/man3/setfilecon_raw.3 b/selinux/libselinux/man/man3/setfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/selinux/libselinux/man/man3/setfilecon_raw.3
@@ -0,0 +1 @@ +.so man3/setfilecon.3
diff --git a/selinux/libselinux/man/man3/setfscreatecon.3 b/selinux/libselinux/man/man3/setfscreatecon.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/selinux/libselinux/man/man3/setfscreatecon.3
@@ -0,0 +1 @@ +.so man3/getfscreatecon.3
diff --git a/selinux/libselinux/man/man3/setfscreatecon_raw.3 b/selinux/libselinux/man/man3/setfscreatecon_raw.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/selinux/libselinux/man/man3/setfscreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getfscreatecon.3
diff --git a/selinux/libselinux/man/man3/setkeycreatecon.3 b/selinux/libselinux/man/man3/setkeycreatecon.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/selinux/libselinux/man/man3/setkeycreatecon.3
@@ -0,0 +1 @@ +.so man3/getkeycreatecon.3
diff --git a/selinux/libselinux/man/man3/setkeycreatecon_raw.3 b/selinux/libselinux/man/man3/setkeycreatecon_raw.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/selinux/libselinux/man/man3/setkeycreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getkeycreatecon.3
diff --git a/selinux/libselinux/man/man3/setsockcreatecon.3 b/selinux/libselinux/man/man3/setsockcreatecon.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/selinux/libselinux/man/man3/setsockcreatecon.3
@@ -0,0 +1 @@ +.so man3/getsockcreatecon.3
diff --git a/selinux/libselinux/man/man3/setsockcreatecon_raw.3 b/selinux/libselinux/man/man3/setsockcreatecon_raw.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/selinux/libselinux/man/man3/setsockcreatecon_raw.3
@@ -0,0 +1 @@ +.so man3/getsockcreatecon.3
diff --git a/selinux/libselinux/man/man3/sidget.3 b/selinux/libselinux/man/man3/sidget.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/selinux/libselinux/man/man3/sidget.3
@@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3
diff --git a/selinux/libselinux/man/man3/sidput.3 b/selinux/libselinux/man/man3/sidput.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/selinux/libselinux/man/man3/sidput.3
@@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3
diff --git a/selinux/libselinux/man/man3/string_to_av_perm.3 b/selinux/libselinux/man/man3/string_to_av_perm.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/string_to_av_perm.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man3/string_to_security_class.3 b/selinux/libselinux/man/man3/string_to_security_class.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/selinux/libselinux/man/man3/string_to_security_class.3
@@ -0,0 +1 @@ +.so man3/security_class_to_string.3
diff --git a/selinux/libselinux/man/man5/booleans.5 b/selinux/libselinux/man/man5/booleans.5 new file mode 100644 index 0000000..2e9caa7 --- /dev/null +++ b/selinux/libselinux/man/man5/booleans.5
@@ -0,0 +1,80 @@ +.TH "booleans" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +booleans \- The SELinux booleans configuration files +. +.SH "DESCRIPTION" +The \fIbooleans\fR file, if present contains booleans to support a specific distribution. +.sp +The \fIbooleans.local\fR file, if present contains locally generated booleans. +.sp +Both files contain a list of boolean names and their associated values. +.sp +Generally the \fIbooleans\fR and/or \fIbooleans.local\fR files are not present (they have been deprecated). However if there is an SELinux-aware application that uses the libselinux functions listed below, then these files may be present: +.sp +.RS +.BR security_set_boolean_list "(3) " +.RS +Writes a \fIbooleans.local\fR file if flag \fIpermanent\fR = \fI1\fR. +.sp +.RE +.RE +.RS +.BR security_load_booleans "(3) " +.RS +Looks for a \fIbooleans\fR and/or \fIbooleans.local\fR file at \fBselinux_booleans_path\fR(3) unless a specific path is specified as a parameter. +.RE +.RE +.sp +\fBbooleans\fR(8) has details on booleans and \fBsetsebool\fR(8) describes how booleans can now be set persistent across reboots. +.sp +\fBselinux_booleans_path\fR(3) will return the active policy path to these files. The default boolean files are: +.RS +.I /etc/selinux/{SELINUXTYPE}/booleans +.br +.I /etc/selinux/{SELINUXTYPE}/booleans.local +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Both boolean files have the same format and contain one or more boolean names and their value. +.sp +The format is: +.RS +.I boolean_name +.I value +.sp +.RE +Where: +.RS +.I boolean_name +.RS +The name of the boolean. +.RE +.I value +.RS +The default setting for the boolean. This can be one of the following: +.RS +.IR true " | " false " | " 1 " | " 0 +.RE +.RE +.RE +.sp +Note that if +.B SETLOCALDEFS +is set in the SELinux +.I config +file (see +.BR selinux_config "(5)), then " selinux_mkload_policy "(3) will check for a " +.I booleans.local +file in the +.BR selinux_booleans_path (3) +and also a +.I local.users +file (see +.BR local.users "(5)) in the " selinux_users_path "(3). " +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " booleans "(8), " setsebool "(8), " semanage "(8), " selinux_booleans_path "(3), " security_set_boolean_list "(3), " security_load_booleans "(3), " selinux_mkload_policy "(3), " selinux_users_path "(3), " selinux_config "(5), " local.users "(5) "
diff --git a/selinux/libselinux/man/man5/customizable_types.5 b/selinux/libselinux/man/man5/customizable_types.5 new file mode 100644 index 0000000..4924f7b --- /dev/null +++ b/selinux/libselinux/man/man5/customizable_types.5
@@ -0,0 +1,59 @@ +.TH "customizable_types" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +customizable_types \- The SELinux customizable types configuration file +. +.SH "DESCRIPTION" +The \fIcustomizable_types\fR file contains a list of types that can be customised in some way by SELinux-aware applications. +.sp +Generally this is a file context type that is usually set on files that need to be shared among certain domains and where the administrator wants to manually manage the type. +.sp +The use of customizable types is deprecated as the preferred approach is to use +.BR semanage (8) +.BR fcontext (8) +.BR ... (8). +However, SELinux-aware applications such as +.BR setfiles (8) +will use this information to obtain a list of types relating to files that should not be relabeled. +.sp +.BR selinux_customizable_types_path (3) +will return the active policy path to this file. The default customizable types file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/customizable_types +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR is_context_customizable (3) +reads this file to determine if a context is customisable or not for the active policy. +. +.SH "FILE FORMAT" +Each line in the file consists of the following: +.RS +.I type +.RE +.sp +Where: +.RS +.I type +.RS +The type defined in the policy that can be customised. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/customizable_types +.br +mount_loopback_t +.br +public_content_rw_t +.br +public_content_t +.br +swapfile_t +.br +sysadm_untrusted_content_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_customizable_types_path "(3), " is_context_customizable "(3), " semanage "(8), " setfiles "(8), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/default_contexts.5 b/selinux/libselinux/man/man5/default_contexts.5 new file mode 100644 index 0000000..f63d24a --- /dev/null +++ b/selinux/libselinux/man/man5/default_contexts.5
@@ -0,0 +1,71 @@ +.TH "default_contexts" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +default_contexts \- The SELinux default contexts configuration file +. +.SH "DESCRIPTION" +The default contexts configuration file \fIdefault_contexts\fR contains entries that allow SELinux-aware login applications such as +.BR PAM "(8) " +.sp +SELinux-aware login applications generally use one or more of the following libselinux functions that read these files from the active policy path: +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +.sp +The default context configuration file path for the active policy is returned by \fBselinux_default_contexts_path\fR(3). The default, default contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the default configuration file consists of the following: +.RS +.I login_process user_login_process [user_login_process] ... +.RE +.sp +Where: +.RS +.I login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the login process context that are defined in the policy. +.RE +.I user_login_process +.RS +This consists of one or more \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entries that represent the user login process context defined in the policy. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/default_contexts +.br +system_r:crond_t:s0 system_r:system_crond_t:s0 +.br +system_r:local_login_t:s0 user_r:user_t:s0 staff_r:staff_t:s0 +.br +system_r:remote_login_t:s0 user_r:user_t:s0 +.br +system_r:sshd_t:s0 user_r:user_t:s0 +.br +system_r:sulogin_t:s0 sysadm_r:sysadm_t:s0 +.br +system_r:xdm_t:s0 user_r:user_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_default_contexts_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/default_type.5 b/selinux/libselinux/man/man5/default_type.5 new file mode 100644 index 0000000..082a5f0 --- /dev/null +++ b/selinux/libselinux/man/man5/default_type.5
@@ -0,0 +1,39 @@ +.TH "default_type" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +default_type \- The SELinux default type configuration file +. +.SH "DESCRIPTION" +The \fIdefault_type\fR file contains entries that allow SELinux-aware applications such as \fBnewrole\fR(1) to select a default type for a role if one is not supplied. +.sp +\fBselinux_default_type_path\fR(3) will return the active policy path to this file. The default, default type file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_type +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +\fBget_default_type\fR(3) reads this file to determine a type for the active policy. +. +.SH "FILE FORMAT" +Each line within the \fIdefault_type\fR file is formatted with \fIrole\fB:\fItype\fR entries where: +.RS +.I role +.RS +The SELinux role. +.RE +.I type +.RS +The domain type that is returned for this role. +.RE +. +.SH "EXAMPLE" +# ./contexts/default_type +.br +auditadm_r:auditadm_t +.br +user_r:user_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " get_default_type "(3), " newrole "(1), " selinux_default_type_path "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/failsafe_context.5 b/selinux/libselinux/man/man5/failsafe_context.5 new file mode 100644 index 0000000..e7032e5 --- /dev/null +++ b/selinux/libselinux/man/man5/failsafe_context.5
@@ -0,0 +1,64 @@ +.TH "failsafe_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +failsafe_context \- The SELinux fail safe context configuration file +. +.SH "DESCRIPTION" +The +.I failsafe_context +file allows SELinux-aware applications such as +.BR PAM "(8) " +to obtain a known valid login context for an administrator if no valid default entries can be found elsewhere. +.sp +.BR selinux_failsafe_context_path "(3) " +will return the active policy path to this file. The default failsafe context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/failsafe_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The following functions read this file from the active policy path if they cannot obtain a default context: +.br +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +. +.SH "FILE FORMAT" +The file consists of a single line entry as follows: +.RS +\fIrole\fB:\fItype\fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I role +.I type +.I range +.RS +A role, type and optional range (for MCS/MLS), separated by colons (:) to form a valid login process context for an administrator to access the system. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/failsafe_context +.br +unconfined_r:unconfined_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_failsafe_context_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/file_contexts.5 b/selinux/libselinux/man/man5/file_contexts.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/selinux/libselinux/man/man5/file_contexts.5
@@ -0,0 +1 @@ +.so man5/selabel_file.5
diff --git a/selinux/libselinux/man/man5/file_contexts.homedirs.5 b/selinux/libselinux/man/man5/file_contexts.homedirs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/selinux/libselinux/man/man5/file_contexts.homedirs.5
@@ -0,0 +1 @@ +.so man5/selabel_file.5
diff --git a/selinux/libselinux/man/man5/file_contexts.local.5 b/selinux/libselinux/man/man5/file_contexts.local.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/selinux/libselinux/man/man5/file_contexts.local.5
@@ -0,0 +1 @@ +.so man5/selabel_file.5
diff --git a/selinux/libselinux/man/man5/file_contexts.subs.5 b/selinux/libselinux/man/man5/file_contexts.subs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/selinux/libselinux/man/man5/file_contexts.subs.5
@@ -0,0 +1 @@ +.so man5/selabel_file.5
diff --git a/selinux/libselinux/man/man5/file_contexts.subs_dist.5 b/selinux/libselinux/man/man5/file_contexts.subs_dist.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/selinux/libselinux/man/man5/file_contexts.subs_dist.5
@@ -0,0 +1 @@ +.so man5/selabel_file.5
diff --git a/selinux/libselinux/man/man5/local.users.5 b/selinux/libselinux/man/man5/local.users.5 new file mode 100644 index 0000000..94d4673 --- /dev/null +++ b/selinux/libselinux/man/man5/local.users.5
@@ -0,0 +1,68 @@ +.TH "local.users" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +local.users \- The SELinux local users configuration file +. +.SH "DESCRIPTION" +The file contains local user definitions in the form of policy language user statements and is only found on older SELinux systems as it has been deprecated and replaced by the \fBsemange\fR(8) services. +.sp +This file is only read by \fBselinux_mkload_policy\fR(3) when \fBSETLOCALDEFS\fR in the SELinux \fIconfig\fR file (see \fBselinux_config\fR(5)) is set to \fI1\fR. +.sp +.BR selinux_users_path "(3) " +will return the active policy path to the directory where this file is located. The default local users file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/local.users +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +The file consists of one or more entries terminated with '\fB;\fR', each on a separate line as follows: +.RS +\fBuser \fIseuser_id \fBroles \fIrole_id\fR [[\fBlevel \fIlevel\fR] [\fBrange \fIrange\fR]]\fB;\fR +.RE +.sp +Where: +.RS +.B user +.RS +The user keyword. +.RE +.I seuser_id +.RS +The SELinux user identifier. +.RE +.B roles +.RS +The roles keyword. +.RE +.I role_id +.RS +One or more previously declared role identifiers. Multiple role identifiers consist of a space separated list enclosed in braces '{}'. +.RE +.B level +.RS +If MLS/MCS is configured, the level keyword. +.RE +.I level +.RS +The users default security level. Note that only the sensitivity component of the level (e.g. s0) is required. +.RE +.B range +.RS +If MLS/MCS is configured, the range keyword. +.RE +.I range +.RS +The current and clearance levels that the user can run. These are separated by a hyphen '\fB-\fR' as shown in the \fBEXAMPLE\fR section. +.RE +.RE +. +.SH "EXAMPLE" +# ./users/local.users +.br +user test_u roles staff_r level s0 range s0 \- s15:c0.c1023; +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " semanage "(8), " selinux_users_path "(3), " selinux_config "(5), " selinux_mkload_policy "(3) "
diff --git a/selinux/libselinux/man/man5/media.5 b/selinux/libselinux/man/man5/media.5 new file mode 100644 index 0000000..14f00f2 --- /dev/null +++ b/selinux/libselinux/man/man5/media.5
@@ -0,0 +1 @@ +.so man5/selabel_media.5
diff --git a/selinux/libselinux/man/man5/removable_context.5 b/selinux/libselinux/man/man5/removable_context.5 new file mode 100644 index 0000000..60aaa93 --- /dev/null +++ b/selinux/libselinux/man/man5/removable_context.5
@@ -0,0 +1,37 @@ +.TH "removable_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +removable_context \- The SELinux removable devices context configuration file +. +.SH "DESCRIPTION" +This file contains the default label that should be used for removable devices that are not defined in the \fImedia\fR file (that is described in +.BR selabel_media "(5)). " +.sp +.BR selinux_removable_context_path "(3) " +will return the active policy path to this file. The default removable context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/removable_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +The file consists of a single line entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that will be applied to removable devices. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/removable_contexts +.br +system_u:object_r:removable_t:s0 +. +.SH "SEE ALSO" +.BR selinux "(8), " selinux_removable_context_path "(3), " selabel_media "(5), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/secolor.conf.5 b/selinux/libselinux/man/man5/secolor.conf.5 new file mode 100644 index 0000000..b834577 --- /dev/null +++ b/selinux/libselinux/man/man5/secolor.conf.5
@@ -0,0 +1,178 @@ +.TH "secolor.conf" "5" "08 April 2011" "SELinux API documentation" +.SH "NAME" +secolor.conf \- The SELinux color configuration file +. +.SH "DESCRIPTION" +This optional file controls the color to be associated to the context components associated to the +.I raw +context passed by +.BR selinux_raw_context_to_color "(3)," +when context related information is to be displayed in color by an SELinux-aware application. +.sp +.BR selinux_raw_context_to_color "(3)" +obtains this color information from the active policy +.B secolor.conf +file as returned by +.BR selinux_colors_path "(3)." +. +.SH "FILE FORMAT" +The file format is as follows: +.RS +.B color +.I color_name +.BI "= #"color_mask +.br +[...] +.sp +.I context_component string +.B = +.I fg_color_name bg_color_name +.br +[...] +.sp +.RE + +Where: +.br +.B color +.RS +The color keyword. Each color entry is on a new line. +.RE +.I color_name +.RS +A single word name for the color (e.g. red). +.RE +.I color_mask +.RS +A color mask starting with a hash (#) that describes the hexadecimal RGB colors with black being #000000 and white being #ffffff. +.RE +.I context_component +.RS +The context component name that must be one of the following: +.br +.RS +user, role, type or range +.RE +Each +.IR context_component " " string " ..." +entry is on a new line. +.RE +.I string +.RS +This is the +.I context_component +string that will be matched with the +.I raw +context component passed by +.BR selinux_raw_context_to_color "(3)." +.br +A wildcard '*' may be used to match any undefined string for the user, role and type +.I context_component +entries only. +.RE + +.I fg_color_name +.RS +The color_name string that will be used as the foreground color. +A +.I color_mask +may also be used. +.RE +.I bg_color_name +.RS +The color_name string that will be used as the background color. +A +.I color_mask +may also be used. +.RE +. +.SH "EXAMPLES" +Example 1 entries are: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #D2B48C +.sp +user * = black white +.br +role * = white black +.br +type * = tan orange +.br +range s0\-s0:c0.c1023 = black green +.br +range s1\-s1:c0.c1023 = white green +.br +range s3\-s3:c0.c1023 = black tan +.br +range s5\-s5:c0.c1023 = white blue +.br +range s7\-s7:c0.c1023 = black red +.br +range s9\-s9:c0.c1023 = black orange +.br +range s15:c0.c1023 = black yellow +.RE + +.sp +Example 2 entries are: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #d2b48c +.sp +user unconfined_u = #ff0000 green +.br +role unconfined_r = red #ffffff +.br +type unconfined_t = red orange +.br +user user_u = black green +.br +role user_r = white black +.br +type user_t = tan red +.br +user xguest_u = black yellow +.br +role xguest_r = black red +.br +type xguest_t = black green +.br +user sysadm_u = white black +.br +range s0:c0.c1023 = black white +.br +user * = black white +.br +role * = black white +.br +type * = black white +.RE +. +.SH "SEE ALSO" +.BR selinux "(8), " selinux_raw_context_to_color "(3), " selinux_colors_path "(3)"
diff --git a/selinux/libselinux/man/man5/securetty_types.5 b/selinux/libselinux/man/man5/securetty_types.5 new file mode 100644 index 0000000..dbc5c2e --- /dev/null +++ b/selinux/libselinux/man/man5/securetty_types.5
@@ -0,0 +1,45 @@ +.TH "securetty_types" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +securetty_types \- The SELinux secure tty type configuration file +. +.SH "DESCRIPTION" +The +.I securetty_types +file contains a list of types associated to secure tty type that are defined in the policy for use by SELinux-aware applications. +.sp +.BR selinux_securetty_types_path "(3) " +will return the active policy path to this file. The default securetty types file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/securetty_types +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR selinux_check_securetty_context "(3) reads this file to determine if a context is for a secure tty defined in the active policy. " +.sp +SELinux-aware applications such as +.BR newrole "(1) use this information to check the status of a tty. " +. +.SH "FILE FORMAT" +Each line in the file consists of the following entry: +.sp +.RS +.I type +.RS +One or more type entries that are defined in the policy for secure tty devices. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/securetty_types +.br +sysadm_tty_device_t +.br +user_tty_device_t +.br +staff_tty_device_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_securetty_types_path "(3), " newrole "(1), " selinux_check_securetty_context "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/selabel_db.5 b/selinux/libselinux/man/man5/selabel_db.5 new file mode 100644 index 0000000..76eb9bc --- /dev/null +++ b/selinux/libselinux/man/man5/selabel_db.5
@@ -0,0 +1,219 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: KaiGai Kohei <kaigai@ak.jp.nec.com> 2009 +.TH "selabel_db" "5" "01 DEC 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_db \- userspace SELinux labeling interface and configuration file format for the RDBMS objects context backend +. +.SH "SYNOPSIS" +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "DESCRIPTION" +The DB contexts backend maps from a pair of object name and class into security contexts. It is used to find the appropriate context for database objects when relabeling a certain database. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +The \fIobject_name\fR should be a fully qualified name using the hierarchy of database objects. For example, the \fBpg_class\fR table in the \fBpostgres\fR database and \fBpg_catalog\fR schema should be qualified as: +.RS +.B Bpostgres.pg_catalog.pg_class +.RE +.sp +The \fBNOTES\fR section has further information on database support for namespace hierarchies. +.sp +The \fIobject_type\fR argument should be set to one of the following values: +.RS +.TP +.B SELABEL_DB_DATABASE +The +.I object_name +argument specifies the name of a database itself, such as "postgres". +.TP +.B SELABEL_DB_SCHEMA +The +.I object_name +argument specifies the name of a schema object, such as "postgres.public". +.TP +.B SELABEL_DB_TABLE +The +.I object_name +argument specifies the name of a table object, such as "postgres.public.my_table" +.TP +.B SELABEL_DB_COLUMN +The +.I object_name +argument specifies the name of a column object, such as "postgres.public.my_table.user_id" +.TP +.B SELABEL_DB_TUPLE +The +.I object_name +argument specifies the name of a table object which contains the tuples to be relabeled, such as "postgresql.public.my_table". Note that we have no way to identify individual tuple objects, except for WHERE clause on DML statements, because it has no name. +.TP +.B SELABEL_DB_PROCEDURE +The +.I object_name +argument specifies the name of a procedure object, such as "postgres.public.my_func". Note that we don't support lookup of individual security contexts for procedures which have the same name but different arguments. +.TP +.B SELABEL_DB_SEQUENCE +The +.I object_name +argument specifies the name of a sequence object, such as "postgres.public.my_seq". +.TP +.B SELABEL_DB_BLOB +The +.I object_name +argument specifies the name of a large object, such as "postgres.16308". +Note that a large object does not have a name, so it is identified by its identifier value. +.TP +.B SELABEL_DB_VIEW +The +.I object_name +argument specifies the name of a view object, such as "postgres.public.my_view". +.TP +.B SELABEL_DB_LANGUAGE +The +.I object_name +argument specifies the name of a language object, such as "postgres.public.tcl". +.TP +.B SELABEL_DB_EXCEPTION +The +.I object_name +argument specifies the name of a exception object. +.TP +.B SELABEL_DB_DATATYPE +The +.I object_name +argument specifies the name of a type or domain object, such as postgres.public.my_type. +.RE +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the database object context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard DB contexts file. +It tries to open the specfile designed for SE-PostgreSQL as default, so if another RDBMS uses this interface, it needs to give an explicit specfile designed for that RDBMS (see the \fBFILES\fR section for details). +.RE +. +.SH "FILES" +The database context file used to retrieve a context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy database contexts location (as returned by \fBselinux_sepgsql_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used (this option must be used to support databases other than SE-PostgreSQL). +.sp +The default database object contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/sepgsql_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The entries within the database contexts file are shown in the \fBObject Name String Values\fR and \fBFILE FORMAT\fR sections. +. +.SH "Object Name String Values" +The string name assigned to each \fIobject_type\fR argument that can be present in the database contexts file are: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Text Name +SELABEL_DB_DATABASE@db_database +SELABEL_DB_SCHEMA@db_schema +SELABEL_DB_VIEW@db_view +SELABEL_DB_LANGUAGE@db_language +SELABEL_DB_TABLE@db_table +SELABEL_DB_COLUMN@db_column +SELABEL_DB_TUPLE@db_tuple +SELABEL_DB_PROCEDURE@db_procedure +SELABEL_DB_SEQUENCE@db_sequence +SELABEL_DB_BLOB@db_blob +SELABEL_DB_EXCEPTION@db_exception +SELABEL_DB_DATATYPE@db_datatype +.TE +. +.SH "FILE FORMAT" +Each line within the database contexts file is as follows: +.RS +.I object_type object_name context +.RE +.sp +Where: +.RS +.I object_type +.RS +This is the string representation of the object type shown in the \fBObject Name String Values\fR section. +.RE +.I object_name +.RS +The key used to obtain the context based on the \fIobject_type\fR. +.sp +The entry can contain '*' for wildcard matching or '?' for substitution. +.sp +Note that if the '*' is used, then be aware that the order of entries in the file is important. The '*' on its own is used to ensure a default fallback context is assigned and should be the last entry in the \fIobject_type\fR block. +.RE +.I context +.RS +The security context that will be applied to the object. +.RE +.RE +.sp +The following example is for SE-PostgreSQL: +.sp +# ./contexts/sepgsql_contexts file +.br +# object_type object_name context +.br +db_database my_database system_u:object_r:sepgsql_db_t:s0 +.br +db_database * system_u:object_r:sepgsql_db_t:s0 +.br +db_schema *.* system_u:object_r:sepgsql_schema_t:s0 +.br +db_tuple row_low system_u:object_r:sepgsql_table_t:s0 +.br +db_tuple row_high system_u:object_r:sepgsql_table_t:s0:c1023 +.br +db_tuple *.*.* system_u:object_r:sepgsql_table_t:s0 +. +.SH "NOTES" +.IP "1." 4 +A suitable database contexts file needs to be written for the target RDBMS and the \fBSELABEL_OPT_PATH\fR option must be used in \fBselabel_open\fR(3) to load it. +.IP "2." 4 +The hierarchy of the namespace for database objects depends on the RDBMS, however the \fIselabel*\fR interfaces do not have any specific support for a namespace hierarchy. +.sp +SE-PostgreSQL has a namespace hierarchy where a database is the top level object with the schema being the next level. Under the schema object there can be other types of objects such as tables and procedures. This hierarchy is supported as follows: +.RS +.RS +.sp +If a security context is required for "my_table" table in the "public" +schema within the "postgres" database, then the \fBselabel_lookup\fR(3) +parameters for \fIobject_type\fR would be \fBSELABEL_DB_TABLE\fR and the +\fIobject_name\fR would be "postgres.public.my_table", the security +context (if available), would be returned in \fIcontext\fR. +.RE +.RE +.IP "3." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_sepgsql_context_path "(3), " freecon "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/selabel_file.5 b/selinux/libselinux/man/man5/selabel_file.5 new file mode 100644 index 0000000..e738824 --- /dev/null +++ b/selinux/libselinux/man/man5/selabel_file.5
@@ -0,0 +1,220 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_file" "5" "01 Dec 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_file \- userspace SELinux labeling interface and configuration file format for the file contexts backend +. +.SH "SYNOPSIS" +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +. +.SH "DESCRIPTION" +The file contexts backend maps from pathname/mode combinations into security contexts. It is used to find the appropriate context for each file when relabeling a file system. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes, however the following \fIerrno\fR is clarified further for the file contexts backend: +.RS +.TP +.B ENOENT +No context corresponding to the \fIpath\fR and \fImode\fR was found - This will also be returned when the file contexts series of files have a context of \fB<<none>>\fR against the \fIpath\fR (see the \fBFILE FORMAT\fR section). +.RE +.sp +The \fIpath\fR argument should be set to the full pathname of the file whose assigned context is being checked. The \fImode\fR argument should be set to the mode bits of the file, as determined by \fBlstat\fR(2). \fImode\fR may be zero, however full matching may not occur. +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine a file context. +. +.SH "OPTIONS" +In addition to the global options described in +.BR selabel_open (3), +this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard file contexts file. This value is also used as the base name for determining the names of local customization files. +.TP +.B SELABEL_OPT_BASEONLY +A non-null value for this option indicates that any local customizations to the file contexts mapping should be ignored. +.TP +.B SELABEL_OPT_SUBSET +A non-null value for this option is interpreted as a path prefix, for example "/etc". Only file context specifications with starting with a first component that prefix matches the given prefix are loaded. This may increase lookup performance, however any attempt to look up a path not starting with the given prefix may fail. This optimization is no longer required due to the use of +.I file_contexts.bin +files and is deprecated. +.RE +. +.SH "FILES" +The file context files used to retrieve the default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy file contexts location (as returned by \fBselinux_file_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +If \fBSELABEL_OPT_BASEONLY\fR is set, then the following files will be processed: +.RS +.IP "1." 4 +The mandatory file contexts file that is either the fully qualified file name from \fISELABEL_OPT_PATH.value\fR or if \fINULL\fR, then the path returned by \fBselinux_file_context_path\fR(3). +.IP "2." 4 +The optional local and distribution substitution files that perform path aliasing on the 'in memory' version of the file contexts file. +.br +These files have the same name as the mandatory file contexts file with the extensions \fI.subs\fR and \fI.subs_dist\fR added. +.RE +.sp +If the \fBSELABEL_OPT_BASEONLY\fR is not set, then the following files will be processed: +.RS +.IP "1." 4 +The mandatory file contexts file that is either the fully qualified file name from \fISELABEL_OPT_PATH.value\fR or if \fINULL\fR, then the path returned by \fBselinux_file_context_path\fR(3). +.IP "2." 4 +The optional local customizations file that has the same name as the mandatory file contexts file with the extension \fI.local\fR added. +.br +\fBselinux_file_context_local_path\fR(3) will return the default path to this file. +.IP "3." 4 +The optional user home directory customizations file that has the same name as the mandatory file contexts file with the extension \fI.homedirs\fR added. +.br +\fBselinux_file_context_homedir_path\fR(3) will return the default path to this file. +.IP "4." 4 +The optional local and distribution substitution files that perform any path aliasing on the 'in memory' version of the file contexts file (and the \fI.local\fR and/or \fI.homedirs\fR if present). These files have the same name as the mandatory file contexts file with the extensions \fI.subs\fR and \fI.subs_dist\fR added. +.br +\fBselinux_file_context_subs_path\fR(3) and \fBselinux_file_context_subs_dist_path\fR(3) will return the default paths to these files. +.RE +.sp +The default file context series of files are: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.local +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.homedirs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs_dist +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +Only the \fIfile_contexts\fR file is mandatory, the remainder are optional. +.sp +The entries within the file contexts series of files are shown in the \fBFILE FORMAT\fR section. +. +.SH "FILE FORMAT" +.sp +.SH "File Contexts Format" +.sp +Each line within the \fIfile_contexts\fR and the two customization files (\fI.local\fR and \fI.homedirs\fR) is as follows: +.sp +.RS +.I pathname [file_type] context +.RE +.sp +Where: +.br +.RS +.I pathname +.RS +An entry that defines the pathname that may be in the form of a regular expression. +.RE +.I file_type +.RS +An optional file type consisting of: +.RS +\fI\-b\fR - Block Device \fI\-c\fR - Character Device +.br +\fI\-d\fR - Directory \fI\-p\fR - Named Pipe +.br +\fI\-l\fR - Symbolic Link \fI\-s\fR - Socket +.br +\fI\-\-\fR - Ordinary file +.RE +.RE +.I context +.RS +This entry can be either: +.RS +.IP "a." 4 +The security context that will be assigned to the file (i.e. returned as \fIcontext\fR). +.IP "b." 4 +A value of \fB<<none>>\fR can be used to indicate that the matching files should not be re-labeled and causes \fBselabel_lookup\fR(3) to return \-1 with \fIerrno\fR set to \fBENOENT\fR. +.RE +.RE +.RE +.sp +Example: +.RS +# ./contexts/files/file_contexts +.br +# pathname file_type context +.br +/.* system_u:object_r:default_t:s0 +.br +/[^/]+ \-\- system_u:object_r:etc_runtime_t:s0 +.br +/tmp/.* <<none>> +.RE +.sp +.SH "Substitution File Format" +.sp +Each line within the substitution files (\fI.subs\fR and \fI.subs_dist\fR) has the form: +.RS +.I subs_pathname pathname +.RE +.sp +Where: +.RS +.I pathname +.RS +A path that matches an entry in one or more of the file contexts policy configuration file. +.RE +.I subs_pathname +.RS +The path that will be aliased (considered equivalent) with pathname by the look up process. +.RE +.RE +.sp +Example: +.RS +# ./contexts/files/file_contexts.subs +.br +# pathname subs_pathname +.br +/myweb /var/www +.br +/myspool /var/spool/mail +.sp +Using the above example, when \fBselabel_lookup\fR(3) is passed a path of +\fI/myweb/index.html\fR the function will substitute the \fI/myweb\fR +component with \fI/var/www\fR, therefore the path used is: +.sp +.RS +.I /var/www/index.html +.RE +.RE +. +.SH "NOTES" +.IP "1." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +.IP "2." 4 +If the size of file contexts series of files contain many entries, then \fBselabel_open\fR(3) may have a delay as it reads in the files, and if +requested validates the entries. +.IP "3." 4 +Depending on the version of SELinux it is possible that a \fIfile_contexts.template\fR file may also be present, however this is now deprecated. +.br +The template file has the same format as the \fIfile_contexts\fR file and may also contain the keywords \fBHOME_ROOT\fR, \fBHOME_DIR\fR, \fBROLE\fR and \fBUSER\fR. This functionality has now been moved to the policy store and managed by \fBsemodule\fR(8) and \fBgenhomedircon\fR(8). +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_file_context_path "(3), " freecon "(3), " selinux_config "(5), " lstat "(2), "selinux_file_context_subs_path "(3), " selinux_file_context_subs_dist_path "(3), " selinux_file_context_homedir_path "(3), "selinux_file_context_local_path "(3), " semodule "(8), " genhomedircon "(8) "
diff --git a/selinux/libselinux/man/man5/selabel_media.5 b/selinux/libselinux/man/man5/selabel_media.5 new file mode 100644 index 0000000..395ed0e --- /dev/null +++ b/selinux/libselinux/man/man5/selabel_media.5
@@ -0,0 +1,93 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_media" "5" "29 Nov 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_media \- userspace SELinux labeling interface and configuration file format for the media contexts backend +. +.SH "SYNOPSIS" +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +. +.SH "DESCRIPTION" +The media contexts backend maps from media device names such as "cdrom" or "floppy" into security contexts. It is used to find the appropriate context for establishing context mounts on these devices. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +The integer lookup argument is currently unused and should be set to zero. +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the media context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard \fImedia\fR contexts file. +. +.SH "FILES" +The media context file used to retrieve a default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\FR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy media contexts location (as returned by \fBselinux_media_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +The default media contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/files/media +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +Should there not be a valid entry in the \fImedia\fR file, then the default \fIremovable_context\fR file will be read (see \fBremovable_context\fR(5)). +. +.SH "FILE FORMAT" +Each line within the \fImedia\fR file is as follows: +.RS +.I device_name context +.RE +.sp +Where: +.RS +.I device_name +.RS +The media identifier (e.g. cdrom, floppy, disk and usb). +.RE +.I context +.RS +The context to be used for labeling the device. +.RE +.RE +.sp +Example: +.RS +# contexts/files/media +.br +cdrom system_u:object_r:removable_device_t +.br +floppy system_u:object_r:removable_device_t +.br +disk system_u:object_r:fixed_disk_device_t +. +.SH "NOTES" +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If +this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_media_context_path "(3), " freecon "(3), " selinux_config "(5), " removable_context "(5) "
diff --git a/selinux/libselinux/man/man5/selabel_x.5 b/selinux/libselinux/man/man5/selabel_x.5 new file mode 100644 index 0000000..198a3e1 --- /dev/null +++ b/selinux/libselinux/man/man5/selabel_x.5
@@ -0,0 +1,166 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_x" "5" "29 Nov 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_x \- userspace SELinux labeling interface and configuration file format for the X Window System contexts backend. This backend is also used to determine the default context for labeling remotely connected X clients +. +.SH "SYNOPSIS" +.B #include <selinux/label.h> +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "DESCRIPTION" +The X contexts backend maps from X Window System object names into security contexts. It is used to find the appropriate context for X Window System objects whose significance and/or usage semantics are determined primarily by name. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +This backend is also used to determine the default context for labeling remotely connected X clients. +.sp +The \fIobject_type\fR argument should be set to one of the following values: +.RS +.TP +.B SELABEL_X_PROP +The +.I object_name +argument specifies the name of a window property, such as "WM_NAME". +.TP +.B SELABEL_X_SELN +The +.I object_name +argument specifies the name of a selection, such as "PRIMARY". +.TP +.B SELABEL_X_EXT +The +.I object_name +argument specifies the name of a protocol extension, such as "RENDER". +.TP +.B SELABEL_X_EVENT +The +.I object_name +argument specifies the name of an event type, such as "X11:ButtonPress". +.TP +.B SELABEL_X_CLIENT +The +.I object_name +argument is ignored, however it should be set to either \fI*\fR (an asterisk or 'wildcard' that will select the default entry) or a specific entry such as "remote" in the X contexts file as shown in the \fBEXAMPLE\fR section. The default context for labeling remote X clients is then returned. +.TP +.B SELABEL_X_POLYPROP +Like +.BR SELABEL_X_PROP , +but checks if the property was marked as being polyinstantiated. See \fBNOTES\fR below. +.TP +.B SELABEL_X_POLYSELN +Like +.BR SELABEL_X_SELN , +but checks if the selection was marked as being polyinstantiated. See \fBNOTES\fR below. +.RE +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.B selabel_lookup_raw +behaves identically to \fBselabel_lookup\fR but does not perform context translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the X object context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard X contexts file (see the \fBFILES\fR section for details). +.RE +. +.SH "FILES" +The X context file used to retrieve a default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy X contexts location (as returned by \fBselinux_x_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +The default X object contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/x_contexts +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The entries within the X contexts file are shown in the \fBObject Name String Values\fR and \fBFILE FORMAT\fR sections. +. +.SH "Object Name String Values" +The string name assigned to each \fIobject_type\fR argument that can be present in the X contexts file are: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Text Name +SELABEL_X_PROP@property +SELABEL_X_SELN@selection +SELABEL_X_EXT@extension +SELABEL_X_EVENT@event +SELABEL_X_CLIENT@client +SELABEL_X_POLYPROP@poly_property +SELABEL_X_POLYSELN@poly_selection +.TE +. +.SH "FILE FORMAT" +Each line within the X contexts file is as follows: +.RS +.I object_type object_name context +.RE +.sp +Where: +.RS +.I object_type +.RS +This is the string representation of the object type shown in the \fBObject Name String Values\fR section. +There can be multiple lines with the same \fIobject_type\fR string that will form a block of entries (each with a different \fIobject_name\fR entry). +.RE +.I object_name +.RS +These are the object names of the specific X-server resource such as +\fBPRIMARY\fR, \fBCUT_BUFFER0\fR etc. They are generally defined in the +X-server source code (\fIprotocol.txt\fR and \fIBuiltInAtoms\fR in the +dix directory of the xorg\-server source package). +The entry can contain '*' for wildcard matching or '?' for substitution. +Note that if the '*' is used, then be aware that the order of entries in the file is important. The '*' on its own is used to ensure a default fallback context is assigned and should be the last entry in the \fIobject_type\fR block. +.RE +.I context +.RS +The security context that will be applied to the object. +.RE +.RE +.sp +Example 1: +.sp +.nf +# object_type object_name context +selection PRIMARY system_u:object_r:clipboard_xselection_t:s0 +selection * system_u:object_r:xselection_t:s0 +.fi +.sp +Example 2 - This example shows how a client entry can be configured to +ensure an entry is always found: +.sp +.nf +# object_type object_name context +client * system_u:object_r:remote_t:s0 +.fi +. +.SH "NOTES" +.IP "1." 4 +Properties and selections are marked as either polyinstantiated or not. For these name types, the "POLY" option searches only the names marked as being polyinstantiated, while the other option searches only the names marked as not being polyinstantiated. Users of the interface should check both mappings, optionally taking action based on the result (e.g. polyinstantiating the object). +.IP "2." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_x_context_path "(3), " freecon "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/sepgsql_contexts.5 b/selinux/libselinux/man/man5/sepgsql_contexts.5 new file mode 100644 index 0000000..ec2bb47 --- /dev/null +++ b/selinux/libselinux/man/man5/sepgsql_contexts.5
@@ -0,0 +1 @@ +.so man5/selabel_db.5
diff --git a/selinux/libselinux/man/man5/service_seusers.5 b/selinux/libselinux/man/man5/service_seusers.5 new file mode 100644 index 0000000..385a326 --- /dev/null +++ b/selinux/libselinux/man/man5/service_seusers.5
@@ -0,0 +1,67 @@ +.TH "service_seusers" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +service_seusers \- The SELinux GNU/Linux user and service to SELinux user mapping configuration files +. +.SH "DESCRIPTION" +These are optional files that allow services to define an SELinux user when authenticating via SELinux-aware login applications such as +.BR PAM "(8). " +.sp +There is one file for each GNU/Linux user name that will be required to run a service with a specific SELinux user name. +.sp +The path for each configuration file is formed by the path returned by +.BR selinux_policy_root "(3) with " +.IR /logins/username +appended (where \fIusername\fR is a file representing the GNU/Linux user name). The default services directory is located at: +.RS +.I /etc/selinux/{SELINUXTYPE}/logins +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR getseuser "(3) reads this file to map services to an SELinux user. " +. +.SH "FILE FORMAT" +Each line within the \fIusername\fR file is formatted as follows with each component separated by a colon: +.RS +.IB service : seuser \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I service +.RS +The service name used by the application. +.RE +.I seuser +.RS +The SELinux user name. +.RE +.I range +.RS +The range for MCS/MLS policies. +.RE +.RE +. +.SH "EXAMPLES" +Example 1 - for the 'root' user: +.RS +# ./logins/root +.br +ipa:user_u:s0 +.br +this_service:unconfined_u:s0 +.RE +.sp +Example 2 - for GNU/Linux user 'rch': +.RS +# ./logins/rch +.br +ipa:unconfined_u:s0 +.br +that_service:unconfined_u:s0 +.RE +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_policy_root "(3), " getseuser "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/seusers.5 b/selinux/libselinux/man/man5/seusers.5 new file mode 100644 index 0000000..2512560 --- /dev/null +++ b/selinux/libselinux/man/man5/seusers.5
@@ -0,0 +1,63 @@ +.TH "seusers" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +seusers \- The SELinux GNU/Linux user to SELinux user mapping configuration file +. +.SH "DESCRIPTION" +The +.I seusers +file contains a list GNU/Linux user to SELinux user mapping for use by SELinux-aware login applications such as \fBPAM\fR(8). +.sp +.BR selinux_usersconf_path "(3) " +will return the active policy path to this file. The default SELinux users mapping file is located at: +.RS +.I /etc/selinux/{SELINUXTYPE}/seusers +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR getseuserbyname "(3) reads this file to map a GNU/Linux user or group to an SELinux user. " +. +.SH "FILE FORMAT" +Each line of the +.I seusers +configuration file consists of the following: +.sp +.RS +\fR[\fB%\fIgroup_id\fR]|[\fIuser_id\fR]\fB:\fIseuser_id\fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +\fIgroup_id\fR|\fIuser_id +.RS +\fRThe GNU/Linux user id, or if preceded by the percentage (\fB%\fR) symbol, then a GNU/Linux group id. +.br +An optional entry set to \fB__default__\fR can be provided as a fall back if required. +.RE +.I seuser_id +.RS +The SELinux user identity. +.RE +.I range +.RS +The optional level or range for an MLS/MCS policy. +.RE +.RE +. +.SH "EXAMPLE" +# ./seusers +.br +system_u:system_u:s0\-s15:c0.c255 +.br +root:root:s0\-s15:c0.c255 +.br +fred:user_u:s0 +.br +__default__:user_u:s0 +.br +%user_group:user_u:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_usersconf_path "(3), " getseuserbyname "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/user_contexts.5 b/selinux/libselinux/man/man5/user_contexts.5 new file mode 100644 index 0000000..fc53d6c --- /dev/null +++ b/selinux/libselinux/man/man5/user_contexts.5
@@ -0,0 +1,82 @@ +.TH "user_contexts" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +user_contexts \- The SELinux user contexts configuration files +. +.SH "DESCRIPTION" +These optional user context configuration files contain entries that allow SELinux-aware login applications such as +.BR PAM (8) +(running in their own process context), to determine the context that a users login session should run under. +.sp +SELinux-aware login applications generally use one or more of the following libselinux functions that read these files from the active policy path: +.RS +.BR get_default_context (3) +.br +.BR get_ordered_context_list (3) +.br +.BR get_ordered_context_list_with_level (3) +.br +.BR get_default_context_with_level (3) +.br +.BR get_default_context_with_role (3) +.br +.BR get_default_context_with_rolelevel (3) +.br +.BR query_user_context (3) +.br +.BR manual_user_enter_context (3) +.RE +.sp +There can be one file for each SELinux user configured on the system. The file path is formed using the path returned by +.BR \%selinux_user_contexts_path (3) +for the active policy, with the SELinux user name appended, for example: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/unconfined_u +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/users/xguest_u +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +These files contain context information as described in the +.B FILE FORMAT +section. +. +.SH "FILE FORMAT" +Each line in the user context configuration file consists of the following: +.RS +.I login_process user_login_process +.RE +.sp +Where: +.RS +.I login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the login process context. +.RE +.I user_login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the user login process context. +.RE +.RE +. +.SH "EXAMPLE" +# Example for xguest_u at /etc/selinux/targeted/contexts/users/xguest_u +.br +system_r:crond_t:s0 xguest_r:xguest_t:s0 +.br +system_r:initrc_t:s0 xguest_r:xguest_t:s0 +.br +system_r:local_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:remote_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:sshd_t:s0 xguest_r:xguest_t:s0 +.br +system_r:xdm_t:s0 xguest_r:xguest_t:s0 +.br +xguest_r:xguest_t:s0 xguest_r:xguest_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_user_contexts_path "(3), " PAM "(8), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/virtual_domain_context.5 b/selinux/libselinux/man/man5/virtual_domain_context.5 new file mode 100644 index 0000000..2f555a0 --- /dev/null +++ b/selinux/libselinux/man/man5/virtual_domain_context.5
@@ -0,0 +1,40 @@ +.TH "virtual_domain_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +virtual_domain_context \- The SELinux virtual machine domain context configuration file +. +.SH "DESCRIPTION" +The +.I virtual_domain_context +file contains a list of domain contexts that are available for use by the SELinux-aware virtulization API libvirt (see \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_domain_context_path "(3) " +will return the active policy path to this file. The default virtual domain context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_domain_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the file consists of an entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that can be used as a virtual domain context. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/virtual_domain_context +.br +system_u:object_r:svirt_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_domain_context_path "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/virtual_image_context.5 b/selinux/libselinux/man/man5/virtual_image_context.5 new file mode 100644 index 0000000..04cbd79 --- /dev/null +++ b/selinux/libselinux/man/man5/virtual_image_context.5
@@ -0,0 +1,42 @@ +.TH "virtual_image_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +virtual_image_context \- The SELinux virtual machine image context configuration file +. +.SH "DESCRIPTION" +The +.I virtual_image_context +file contains a list of image contexts for use by the SELinux-aware virtulization API libvirt (see \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_image_context_path "(3) " +will return the active policy path to this file. The default virtual image context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_image_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the file consists of an entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that can be used as a virtual image context. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/virtual_image_context +.br +system_u:object_r:svirt_image_t:s0 +.br +system_u:object_r:svirt_content_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_image_context_path "(3), " selinux_config "(5) "
diff --git a/selinux/libselinux/man/man5/x_contexts.5 b/selinux/libselinux/man/man5/x_contexts.5 new file mode 100644 index 0000000..3796d2a --- /dev/null +++ b/selinux/libselinux/man/man5/x_contexts.5
@@ -0,0 +1 @@ +.so man5/selabel_x.5
diff --git a/selinux/libselinux/man/man8/avcstat.8 b/selinux/libselinux/man/man8/avcstat.8 new file mode 100644 index 0000000..2c4bce1 --- /dev/null +++ b/selinux/libselinux/man/man8/avcstat.8
@@ -0,0 +1,35 @@ +.TH "avcstat" "8" "18 Nov 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +avcstat \- Display SELinux AVC statistics +. +.SH "SYNOPSIS" +.B avcstat +.RB [ \-c ] +.RB [ \-f +.IR status_file ] +.RI [ interval ] +. +.SH "DESCRIPTION" +Display SELinux AVC statistics. If the +.I interval +parameter is specified, the program will loop, displaying updated +statistics every +.I interval +seconds. +Relative values are displayed by default. +. +.SH OPTIONS +.TP +.B \-c +Display the cumulative values. +.TP +.B \-f +Specifies the location of the AVC statistics file, defaulting to +.IR /sys/fs/selinux/avc/cache_stats . +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +The program was written by James Morris <jmorris@redhat.com>. +. +.SH "SEE ALSO" +.BR selinux (8)
diff --git a/selinux/libselinux/man/man8/booleans.8 b/selinux/libselinux/man/man8/booleans.8 new file mode 100644 index 0000000..d4ca9c4 --- /dev/null +++ b/selinux/libselinux/man/man8/booleans.8
@@ -0,0 +1,58 @@ +.TH "booleans" "8" "11 Aug 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +booleans \- Policy booleans enable runtime customization of SELinux policy +. +.SH "DESCRIPTION" +This manual page describes SELinux policy booleans. +.BR +The SELinux policy can include conditional rules that are enabled or +disabled based on the current values of a set of policy booleans. +These policy booleans allow runtime modification of the security +policy without having to load a new policy. + +For example, the boolean httpd_enable_cgi allows the httpd daemon to +run cgi scripts if it is enabled. If the administrator does not want +to allow execution of cgi scripts, he can simply disable this boolean +value. + +The policy defines a default value for each boolean, typically false. +These default values can be overridden via local settings created via the +.BR setsebool (8) +utility, using +.B \-P +to make the setting persistent across reboots. The +.B system\-config\-securitylevel +tool provides a graphical interface for altering +the settings. The +.BR load_policy (8) +program will preserve +current boolean settings upon a policy reload by default, or can +optionally reset booleans to the boot-time defaults via the +.B \-b +option. + +Boolean values can be listed by using the +.BR getsebool (8) +utility and passing it the +.B \-a +option. + +Boolean values can also be changed at runtime via the +.BR setsebool (8) +utility or the +.BR togglesebool (8) +utility. By default, these utilities only change the +current boolean value and do not affect the persistent settings, +unless the +.B \-P +option is used to setsebool. +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +The SELinux conditional policy support was developed by Tresys Technology. +. +.SH "SEE ALSO" +.BR getsebool (8), +.BR setsebool (8), +.BR selinux (8), +.BR togglesebool (8)
diff --git a/selinux/libselinux/man/man8/getenforce.8 b/selinux/libselinux/man/man8/getenforce.8 new file mode 100644 index 0000000..70b9921 --- /dev/null +++ b/selinux/libselinux/man/man8/getenforce.8
@@ -0,0 +1,18 @@ +.TH "getenforce" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +getenforce \- get the current mode of SELinux +. +.SH "SYNOPSIS" +.B getenforce +. +.SH "DESCRIPTION" +.B getenforce +reports whether SELinux is enforcing, permissive, or disabled. +. +.SH AUTHOR +Dan Walsh, <dwalsh@redhat.com> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setenforce (8), +.BR selinuxenabled (8)
diff --git a/selinux/libselinux/man/man8/getsebool.8 b/selinux/libselinux/man/man8/getsebool.8 new file mode 100644 index 0000000..d70bf1e --- /dev/null +++ b/selinux/libselinux/man/man8/getsebool.8
@@ -0,0 +1,37 @@ +.TH "getsebool" "8" "11 Aug 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +getsebool \- get SELinux boolean value(s) +. +.SH "SYNOPSIS" +.B getsebool +.RB [ \-a ] +.RI [ boolean ] +. +.SH "DESCRIPTION" +.B getsebool +reports where a particular SELinux boolean or +all SELinux booleans are on or off +In certain situations a boolean can be in one state with a pending +change to the other state. getsebool will report this as a pending change. +The pending value indicates +the value that will be applied upon the next boolean commit. + +The setting of boolean values occurs in two stages; first the pending +value is changed, then the booleans are committed, causing their +active values to become their pending values. This allows a group of +booleans to be changed in a single transaction, by setting all of +their pending values as desired and then committing once. +. +.SH OPTIONS +.TP +.B \-a +Show all SELinux booleans. +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +The program was written by Tresys Technology. +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setsebool (8), +.BR booleans (8)
diff --git a/selinux/libselinux/man/man8/matchpathcon.8 b/selinux/libselinux/man/man8/matchpathcon.8 new file mode 100644 index 0000000..50c0d39 --- /dev/null +++ b/selinux/libselinux/man/man8/matchpathcon.8
@@ -0,0 +1,62 @@ +.TH "matchpathcon" "8" "21 April 2005" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +matchpathcon \- get the default SELinux security context for the specified path from the file contexts configuration +. +.SH "SYNOPSIS" +.B matchpathcon +.RB [ \-V ] +.RB [ \-N ] +.RB [ \-n ] +.RB [ \-m +.IR type ] +.RB [ \-f +.IR file_contexts_file ] +.RB [ \-p +.IR prefix ] +.RB [ \-P +.IR policy_root_path ] +.I filepath... +. +.SH "DESCRIPTION" +.BR matchpathcon +queries the system policy and outputs the default security context associated with the filepath. + +.B Note: +Identical paths can have different security contexts, depending on the file +type (regular file, directory, link file, char file ...). + +.B matchpathcon +will also take the file type into consideration in determining the default security context if the file exists. If the file does not exist, no file type matching will occur. +. +.SH OPTIONS +.TP +.BI \-m " type" +Force file type for the lookup. +Valid types are +.BR file ", " dir ", "pipe ", " chr_file ", " blk_file ", " +.BR lnk_file ", " sock_file . +.TP +.B \-n +Do not display path. +.TP +.B \-N +Do not use translations. +.TP +.BI \-f " file_context_file" +Use alternate file_context file +.TP +.BI \-p " prefix" +Use prefix to speed translations +.TP +.BI \-P " policy_root_path" +Use alternate policy root path +.TP +.B \-V +Verify file context on disk matches defaults +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +. +.SH "SEE ALSO" +.BR selinux "(8), " +.BR matchpathcon (3)
diff --git a/selinux/libselinux/man/man8/sefcontext_compile.8 b/selinux/libselinux/man/man8/sefcontext_compile.8 new file mode 100644 index 0000000..4eae173 --- /dev/null +++ b/selinux/libselinux/man/man8/sefcontext_compile.8
@@ -0,0 +1,71 @@ +.TH "sefcontext_compile" "8" "12 Aug 2015" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +sefcontext_compile \- compile file context regular expression files +. +.SH "SYNOPSIS" +.B sefcontext_compile +.RB [ \-o +.IR outputfile ] +.RB [ \-p +.IR policyfile ] +.I inputfile +. +.SH "DESCRIPTION" +.B sefcontext_compile +is used to compile file context regular expressions into +.BR pcre (3) +format. +.sp +The compiled file is used by libselinux file labeling functions. +.sp +By default +.B sefcontext_compile +writes the compiled pcre file with the +.B .bin +suffix appended (e.g. \fIinputfile\fB.bin\fR). +.SH OPTIONS +.TP +.B \-o +Specify an +.I outputfile +that must be a fully qualified file name as the +.B .bin +suffix is not automatically added. +.TP +.B \-p +Specify a binary +.I policyfile +that will be used to validate the context entries in the +.I inputfile +.br +If an invalid context is found the pcre formatted file will not be written and +an error will be returned. + +.SH "RETURN VALUE" +On error -1 is returned. On success 0 is returned. + +.SH "EXAMPLES" +.B Example 1: +.br +sefcontext_compile /etc/selinux/targeted/contexts/files/file_contexts +.sp +Results in the following file being generated: +.RS +/etc/selinux/targeted/contexts/files/file_contexts.bin +.RE +.sp +.B Example 2: +.br +sefcontext_compile -o new_fc.bin /etc/selinux/targeted/contexts/files/file_contexts +.sp +Results in the following file being generated in the cwd: +.RS +new_fc.bin +.RE +. +.SH AUTHOR +Dan Walsh, <dwalsh@redhat.com> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR semanage (8),
diff --git a/selinux/libselinux/man/man8/selinux.8 b/selinux/libselinux/man/man8/selinux.8 new file mode 100644 index 0000000..6f1034b --- /dev/null +++ b/selinux/libselinux/man/man8/selinux.8
@@ -0,0 +1,111 @@ +.TH "selinux" "8" "29 Apr 2005" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +SELinux \- NSA Security-Enhanced Linux (SELinux) +. +.SH "DESCRIPTION" +NSA Security-Enhanced Linux (SELinux) is an implementation of a +flexible mandatory access control architecture in the Linux operating +system. The SELinux architecture provides general support for the +enforcement of many kinds of mandatory access control policies, +including those based on the concepts of Type Enforcement®, Role- +Based Access Control, and Multi-Level Security. Background +information and technical documentation about SELinux can be found at +http://www.nsa.gov/research/selinux. + +The +.I /etc/selinux/config +configuration file controls whether SELinux is +enabled or disabled, and if enabled, whether SELinux operates in +permissive mode or enforcing mode. The +.B SELINUX +variable may be set to +any one of disabled, permissive, or enforcing to select one of these +options. The disabled option completely disables the SELinux kernel +and application code, leaving the system running without any SELinux +protection. The permissive option enables the SELinux code, but +causes it to operate in a mode where accesses that would be denied by +policy are permitted but audited. The enforcing option enables the +SELinux code and causes it to enforce access denials as well as +auditing them. Permissive mode may yield a different set of denials +than enforcing mode, both because enforcing mode will prevent an +operation from proceeding past the first denial and because some +application code will fall back to a less privileged mode of operation +if denied access. + +The +.I /etc/selinux/config +configuration file also controls what policy +is active on the system. SELinux allows for multiple policies to be +installed on the system, but only one policy may be active at any +given time. At present, multiple kinds of SELinux policy exist: targeted, +mls for example. The targeted policy is designed as a policy where most +user processes operate without restrictions, and only specific services are +placed into distinct security domains that are confined by the policy. +For example, the user would run in a completely unconfined domain +while the named daemon or apache daemon would run in a specific domain +tailored to its operation. The MLS (Multi-Level Security) policy is designed +as a policy where all processes are partitioned into fine-grained security +domains and confined by policy. MLS also supports the Bell And LaPadula model, where processes are not only confined by the type but also the level of the data. + +You can +define which policy you will run by setting the +.B SELINUXTYPE +environment variable within +.IR /etc/selinux/config . +You must reboot and possibly relabel if you change the policy type to have it take effect on the system. +The corresponding +policy configuration for each such policy must be installed in the +.I /etc/selinux/{SELINUXTYPE}/ +directories. + +A given SELinux policy can be customized further based on a set of +compile-time tunable options and a set of runtime policy booleans. +.B \%system\-config\-selinux +allows customization of these booleans and tunables. + +Many domains that are protected by SELinux also include SELinux man pages explaining how to customize their policy. +. +.SH "FILE LABELING" +All files, directories, devices ... have a security context/label associated with them. These context are stored in the extended attributes of the file system. +Problems with SELinux often arise from the file system being mislabeled. This can be caused by booting the machine with a non SELinux kernel. If you see an error message containing file_t, that is usually a good indicator that you have a serious problem with file system labeling. + +The best way to relabel the file system is to create the flag file +.I /.autorelabel +and reboot. +.BR system\-config\-selinux , +also has this capability. The +.BR restorecon / fixfiles +commands are also available for relabeling files. +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +. +.SH FILES +.I /etc/selinux/config +. +.SH "SEE ALSO" +.ad l +.nh +.BR booleans (8), +.BR setsebool (8), +.BR sepolicy (8), +.BR system-config-selinux (8), +.BR togglesebool (8), +.BR restorecon (8), +.BR fixfiles (8), +.BR setfiles (8), +.BR semanage (8), +.BR sepolicy(8) + +Every confined service on the system has a man page in the following format: +.br + +.B <servicename>_selinux(8) + +For example, httpd has the +.B httpd_selinux(8) +man page. + +.B man -k selinux + +Will list all SELinux man pages.
diff --git a/selinux/libselinux/man/man8/selinuxenabled.8 b/selinux/libselinux/man/man8/selinuxenabled.8 new file mode 100644 index 0000000..5cd7a62 --- /dev/null +++ b/selinux/libselinux/man/man8/selinuxenabled.8
@@ -0,0 +1,20 @@ +.TH "selinuxenabled" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxenabled \- tool to be used within shell scripts to determine if selinux is enabled +. +.SH "SYNOPSIS" +.B selinuxenabled +. +.SH "DESCRIPTION" +Indicates whether SELinux is enabled or disabled. +. +.SH "EXIT STATUS" +It exits with status 0 if SELinux is enabled and 1 if it is not enabled. +. +.SH AUTHOR +Dan Walsh, <dwalsh@redhat.com> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setenforce (8), +.BR getenforce (8)
diff --git a/selinux/libselinux/man/man8/selinuxexeccon.8 b/selinux/libselinux/man/man8/selinuxexeccon.8 new file mode 100644 index 0000000..194740d --- /dev/null +++ b/selinux/libselinux/man/man8/selinuxexeccon.8
@@ -0,0 +1,27 @@ +.TH "selinuxexeccon" "8" "14 May 2011" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxexeccon \- report SELinux context used for this executable +. +.SH "SYNOPSIS" +.B selinuxexeccon +.I command +.RI [ fromcon ] +. +.SH "DESCRIPTION" +.B selinuxexeccon +reports the SELinux process context for the specified command from the specified context or the current context. +. +.SH EXAMPLE +.nf +# selinuxexeccon /usr/bin/passwd +staff_u:staff_r:passwd_t:s0-s0:c0.c1023 + +# selinuxexeccon /usr/sbin/sendmail system_u:system_r:httpd_t:s0 +system_u:system_r:system_mail_t:s0 +.fi +. +.SH AUTHOR +This manual page was written by Dan Walsh <dwalsh@redhat.com>. +. +.SH "SEE ALSO" +.BR secon (8)
diff --git a/selinux/libselinux/man/man8/setenforce.8 b/selinux/libselinux/man/man8/setenforce.8 new file mode 100644 index 0000000..702041d --- /dev/null +++ b/selinux/libselinux/man/man8/setenforce.8
@@ -0,0 +1,31 @@ +.TH "setenforce" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +setenforce \- modify the mode SELinux is running in +. +.SH "SYNOPSIS" +.B setenforce +.RB [ Enforcing | Permissive | 1 | 0 ] +. +.SH "DESCRIPTION" +Use +.B Enforcing +or +.B 1 +to put SELinux in enforcing mode. +.br +Use +.B Permissive +or +.B 0 +to put SELinux in permissive mode. + +If SELinux is disabled and you want to enable it, or SELinux is enabled and you want to disable it, please see +.BR selinux (8). +. +.SH AUTHOR +Dan Walsh, <dwalsh@redhat.com> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getenforce (8), +.BR selinuxenabled (8)
diff --git a/selinux/libselinux/man/man8/togglesebool.8 b/selinux/libselinux/man/man8/togglesebool.8 new file mode 100644 index 0000000..8f775ca --- /dev/null +++ b/selinux/libselinux/man/man8/togglesebool.8
@@ -0,0 +1,22 @@ +.TH "togglesebool" "8" "26 Oct 2004" "sgrubb@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +togglesebool \- flip the current value of a SELinux boolean +. +.SH "SYNOPSIS" +.B togglesebool +.I boolean... +. +.SH "DESCRIPTION" +.B togglesebool +flips the current value of a list of booleans. If the value is currently a 1, +then it will be changed to a 0 and vice versa. Only the "in memory" values are +changed; the boot-time settings are unaffected. +. +.SH AUTHOR +This man page was written by Steve Grubb <sgrubb@redhat.com> +. +.SH "SEE ALSO" +.BR selinux (8), +.BR booleans (8), +.BR getsebool (8), +.BR setsebool (8)
diff --git a/selinux/libselinux/src/Makefile b/selinux/libselinux/src/Makefile new file mode 100644 index 0000000..ac9a5d6 --- /dev/null +++ b/selinux/libselinux/src/Makefile
@@ -0,0 +1,179 @@ +# Support building the Python bindings multiple times, against various Python +# runtimes (e.g. Python 2 vs Python 3) by optionally prefixing the build +# targets with "PYPREFIX": +PYTHON ?= python +PYPREFIX ?= $(notdir $(PYTHON)) +RUBY ?= ruby +RUBYPREFIX ?= $(notdir $(RUBY)) +PKG_CONFIG ?= pkg-config + +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +LIBDIR ?= $(PREFIX)/lib +SHLIBDIR ?= $(DESTDIR)/lib +INCLUDEDIR ?= $(PREFIX)/include +PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])') +PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX)) +PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER) +RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")') +RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM') +RUBYINC ?= $(shell $(PKG_CONFIG) --cflags ruby) +RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) +LIBBASE ?= $(shell basename $(LIBDIR)) + +VERSION = $(shell cat ../VERSION) +LIBVERSION = 1 + +LIBA=libselinux.a +TARGET=libselinux.so +LIBPC=libselinux.pc +SWIGIF= selinuxswig_python.i selinuxswig_python_exception.i +SWIGRUBYIF= selinuxswig_ruby.i +SWIGCOUT= selinuxswig_wrap.c +SWIGPYOUT= selinux.py +SWIGRUBYCOUT= selinuxswig_ruby_wrap.c +SWIGLOBJ:= $(patsubst %.c,$(PYPREFIX)%.lo,$(SWIGCOUT)) +SWIGRUBYLOBJ:= $(patsubst %.c,%.lo,$(SWIGRUBYCOUT)) +SWIGSO=$(PYPREFIX)_selinux.so +SWIGFILES=$(SWIGSO) $(SWIGPYOUT) +SWIGRUBYSO=$(RUBYPREFIX)_selinux.so +LIBSO=$(TARGET).$(LIBVERSION) +AUDIT2WHYLOBJ=$(PYPREFIX)audit2why.lo +AUDIT2WHYSO=$(PYPREFIX)audit2why.so + +ifeq ($(DISABLE_AVC),y) + UNUSED_SRCS+=avc.c avc_internal.c avc_sidtab.c mapping.c stringrep.c checkAccess.c +endif +ifeq ($(DISABLE_BOOL),y) + UNUSED_SRCS+=booleans.c +endif + +GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) selinuxswig_python_exception.i +SRCS= $(filter-out $(UNUSED_SRCS) $(GENERATED) audit2why.c, $(wildcard *.c)) + +MAX_STACK_SIZE=32768 + +OBJS= $(patsubst %.c,%.o,$(SRCS)) +LOBJS= $(patsubst %.c,%.lo,$(SRCS)) +CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissing-include-dirs \ + -Wunused -Wunknown-pragmas -Wstrict-aliasing -Wshadow -Wpointer-arith \ + -Wbad-function-cast -Wcast-align -Wwrite-strings -Wlogical-op -Waggregate-return \ + -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes \ + -Wmissing-declarations -Wmissing-noreturn -Wmissing-format-attribute \ + -Wredundant-decls -Wnested-externs -Winline -Winvalid-pch -Wvolatile-register-var \ + -Wdisabled-optimization -Wbuiltin-macro-redefined -Wpacked-bitfield-compat \ + -Wsync-nand -Wattributes -Wcoverage-mismatch -Wmultichar -Wcpp \ + -Wdeprecated-declarations -Wdiv-by-zero -Wdouble-promotion -Wendif-labels -Wextra \ + -Wformat-contains-nul -Wformat-extra-args -Wformat-zero-length -Wformat=2 -Wmultichar \ + -Wnormalized=nfc -Woverflow -Wpointer-to-int-cast -Wpragmas -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines \ + -Wno-missing-field-initializers -Wno-sign-compare -Wjump-misses-init \ + -Wno-format-nonliteral -Wframe-larger-than=$(MAX_STACK_SIZE) -Wp,-D_FORTIFY_SOURCE=2 \ + -fstack-protector-all --param=ssp-buffer-size=4 -fexceptions \ + -fasynchronous-unwind-tables -fdiagnostics-show-option -funit-at-a-time \ + -fipa-pure-const -Wno-suggest-attribute=pure -Wno-suggest-attribute=const \ + -Werror -Wno-aggregate-return -Wno-redundant-decls + +override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS) + +SWIG_CFLAGS += -Wno-error -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter \ + -Wno-shadow -Wno-uninitialized -Wno-missing-prototypes -Wno-missing-declarations + +RANLIB ?= ranlib + +ARCH := $(patsubst i%86,i386,$(shell uname -m)) +ifneq (,$(filter i386,$(ARCH))) +TLSFLAGS += -mno-tls-direct-seg-refs +endif + +SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./ $(EMFLAGS) + +SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ $(EMFLAGS) + +all: $(LIBA) $(LIBSO) $(LIBPC) + +pywrap: all $(SWIGFILES) $(AUDIT2WHYSO) + +rubywrap: all $(SWIGRUBYSO) + +$(SWIGLOBJ): $(SWIGCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(PYINC) -fPIC -DSHARED -c -o $@ $< + +$(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< + +$(SWIGSO): $(SWIGLOBJ) + $(CC) $(CFLAGS) -shared -o $@ $< -L. -lselinux $(LDFLAGS) -L$(LIBDIR) + +$(SWIGRUBYSO): $(SWIGRUBYLOBJ) + $(CC) $(CFLAGS) -shared -o $@ $^ -L. -lselinux $(LDFLAGS) -L$(LIBDIR) + +$(LIBA): $(OBJS) + $(AR) rcs $@ $^ + $(RANLIB) $@ + +$(LIBSO): $(LOBJS) + $(CC) $(CFLAGS) -shared -o $@ $^ -lpcre -ldl $(LDFLAGS) -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro + ln -sf $@ $(TARGET) + +$(LIBPC): $(LIBPC).in ../VERSION + sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@ + +selinuxswig_python_exception.i: ../include/selinux/selinux.h + bash exception.sh > $@ + +$(AUDIT2WHYLOBJ): audit2why.c + $(CC) $(filter-out -Werror, $(CFLAGS)) $(PYINC) -fPIC -DSHARED -c -o $@ $< + +$(AUDIT2WHYSO): $(AUDIT2WHYLOBJ) + $(CC) $(CFLAGS) -shared -o $@ $^ -L. $(LDFLAGS) -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) + +%.o: %.c policy.h + $(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $< + +%.lo: %.c policy.h + $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $< + +$(SWIGCOUT): $(SWIGIF) + $(SWIG) $< + +$(SWIGPYOUT): $(SWIGCOUT) + +$(SWIGRUBYCOUT): $(SWIGRUBYIF) + $(SWIGRUBY) $< + +swigify: $(SWIGIF) + $(SWIG) $< + +install: all + test -d $(LIBDIR) || install -m 755 -d $(LIBDIR) + install -m 644 $(LIBA) $(LIBDIR) + test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR) + install -m 755 $(LIBSO) $(SHLIBDIR) + test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig + install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig + ln -sf --relative $(SHLIBDIR)/$(LIBSO) $(LIBDIR)/$(TARGET) + +install-pywrap: pywrap + test -d $(PYLIBDIR)/site-packages/selinux || install -m 755 -d $(PYLIBDIR)/site-packages/selinux + install -m 755 $(SWIGSO) $(PYLIBDIR)/site-packages/selinux/_selinux.so + install -m 755 $(AUDIT2WHYSO) $(PYLIBDIR)/site-packages/selinux/audit2why.so + install -m 644 $(SWIGPYOUT) $(PYLIBDIR)/site-packages/selinux/__init__.py + +install-rubywrap: rubywrap + test -d $(RUBYINSTALL) || install -m 755 -d $(RUBYINSTALL) + install -m 755 $(SWIGRUBYSO) $(RUBYINSTALL)/selinux.so + +relabel: + /sbin/restorecon $(SHLIBDIR)/$(LIBSO) + +clean: + -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(SWIGLOBJ) $(SWIGRUBYLOBJ) $(SWIGSO) $(TARGET) $(AUDIT2WHYSO) *.o *.lo *~ + +distclean: clean + rm -f $(GENERATED) $(SWIGFILES) + +indent: + ../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch])) + +.PHONY: all clean pywrap rubywrap swigify install install-pywrap install-rubywrap distclean
diff --git a/selinux/libselinux/src/audit2why.c b/selinux/libselinux/src/audit2why.c new file mode 100644 index 0000000..12745b3 --- /dev/null +++ b/selinux/libselinux/src/audit2why.c
@@ -0,0 +1,491 @@ +/* Workaround for http://bugs.python.org/issue4835 */ +#ifndef SIZEOF_SOCKET_T +#define SIZEOF_SOCKET_T SIZEOF_INT +#endif + +#include <Python.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <limits.h> +#include <sepol/sepol.h> +#include <sepol/policydb.h> +#include <sepol/policydb/services.h> +#include <selinux/selinux.h> + +#define UNKNOWN -1 +#define BADSCON -2 +#define BADTCON -3 +#define BADTCLASS -4 +#define BADPERM -5 +#define BADCOMPUTE -6 +#define NOPOLICY -7 +#define ALLOW 0 +#define DONTAUDIT 1 +#define TERULE 2 +#define BOOLEAN 3 +#define CONSTRAINT 4 +#define RBAC 5 + +struct boolean_t { + char *name; + int active; +}; + +static struct boolean_t **boollist = NULL; +static int boolcnt = 0; + +struct avc_t { + sepol_handle_t *handle; + sepol_policydb_t *policydb; + sepol_security_id_t ssid; + sepol_security_id_t tsid; + sepol_security_class_t tclass; + sepol_access_vector_t av; +}; + +static struct avc_t *avc = NULL; + +static sidtab_t sidtab; + +static int load_booleans(const sepol_bool_t * boolean, + void *arg __attribute__ ((__unused__))) +{ + boollist[boolcnt] = malloc(sizeof(struct boolean_t)); + boollist[boolcnt]->name = strdup(sepol_bool_get_name(boolean)); + boollist[boolcnt]->active = sepol_bool_get_value(boolean); + boolcnt++; + return 0; +} + +static int check_booleans(struct boolean_t **bools) +{ + char errormsg[PATH_MAX]; + struct sepol_av_decision avd; + unsigned int reason; + int rc; + int i; + sepol_bool_key_t *key = NULL; + sepol_bool_t *boolean = NULL; + int fcnt = 0; + int *foundlist = calloc(boolcnt, sizeof(int)); + if (!foundlist) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + return fcnt; + } + for (i = 0; i < boolcnt; i++) { + char *name = boollist[i]->name; + int active = boollist[i]->active; + rc = sepol_bool_key_create(avc->handle, name, &key); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, + "Could not create boolean key.\n"); + break; + } + rc = sepol_bool_query(avc->handle, + avc->policydb, + key, &boolean); + + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not find boolean %s.\n", name); + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + + sepol_bool_set_value(boolean, !active); + + rc = sepol_bool_set(avc->handle, + avc->policydb, + key, boolean); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not set boolean data %s.\n", name); + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + + /* Reproduce the computation. */ + rc = sepol_compute_av_reason(avc->ssid, avc->tsid, avc->tclass, + avc->av, &avd, &reason); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Error during access vector computation, skipping..."); + PyErr_SetString( PyExc_RuntimeError, errormsg); + + sepol_bool_free(boolean); + break; + } else { + if (!reason) { + foundlist[fcnt] = i; + fcnt++; + } + sepol_bool_set_value(boolean, active); + rc = sepol_bool_set(avc->handle, + avc->policydb, key, + boolean); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not set boolean data %s.\n", + name); + + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + } + sepol_bool_free(boolean); + sepol_bool_key_free(key); + key = NULL; + boolean = NULL; + } + if (key) + sepol_bool_key_free(key); + + if (boolean) + sepol_bool_free(boolean); + + if (fcnt > 0) { + *bools = calloc(sizeof(struct boolean_t), fcnt + 1); + struct boolean_t *b = *bools; + for (i = 0; i < fcnt; i++) { + int ctr = foundlist[i]; + b[i].name = strdup(boollist[ctr]->name); + b[i].active = !boollist[ctr]->active; + } + } + free(foundlist); + return fcnt; +} + +static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) { + PyObject *result = 0; + + if (PyArg_ParseTuple(args,(char *)":finish")) { + int i = 0; + if (! avc) + Py_RETURN_NONE; + + for (i = 0; i < boolcnt; i++) { + free(boollist[i]->name); + free(boollist[i]); + } + free(boollist); + sepol_sidtab_shutdown(&sidtab); + sepol_sidtab_destroy(&sidtab); + sepol_policydb_free(avc->policydb); + sepol_handle_destroy(avc->handle); + free(avc); + avc = NULL; + boollist = NULL; + boolcnt = 0; + + /* Boilerplate to return "None" */ + Py_RETURN_NONE; + } + return result; +} + + +static int __policy_init(const char *init_path) +{ + FILE *fp; + char path[PATH_MAX]; + char errormsg[PATH_MAX]; + struct sepol_policy_file *pf = NULL; + int rc; + unsigned int cnt; + + path[PATH_MAX-1] = '\0'; + if (init_path) { + strncpy(path, init_path, PATH_MAX-1); + fp = fopen(path, "r"); + if (!fp) { + snprintf(errormsg, sizeof(errormsg), + "unable to open %s: %s\n", + path, strerror(errno)); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + } else { + const char *curpolicy = selinux_current_policy_path(); + if (!curpolicy) { + /* SELinux disabled, must use -p option. */ + snprintf(errormsg, sizeof(errormsg), + "You must specify the -p option with the path to the policy file.\n"); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + fp = fopen(curpolicy, "r"); + if (!fp) { + snprintf(errormsg, sizeof(errormsg), + "unable to open %s: %s\n", + curpolicy, + strerror(errno)); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + } + + avc = calloc(sizeof(struct avc_t), 1); + if (!avc) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + fclose(fp); + return 1; + } + + /* Set up a policydb directly so that we can mutate it later + for testing what booleans might have allowed the access. + Otherwise, we'd just use sepol_set_policydb_from_file() here. */ + if (sepol_policy_file_create(&pf) || + sepol_policydb_create(&avc->policydb)) { + snprintf(errormsg, sizeof(errormsg), + "policydb_init failed: %s\n", strerror(errno)); + PyErr_SetString( PyExc_RuntimeError, errormsg); + fclose(fp); + return 1; + } + sepol_policy_file_set_fp(pf, fp); + if (sepol_policydb_read(avc->policydb, pf)) { + snprintf(errormsg, sizeof(errormsg), + "invalid binary policy %s\n", path); + PyErr_SetString( PyExc_ValueError, errormsg); + fclose(fp); + return 1; + } + fclose(fp); + sepol_set_policydb(&avc->policydb->p); + avc->handle = sepol_handle_create(); + /* Turn off messages */ + sepol_msg_set_callback(avc->handle, NULL, NULL); + + rc = sepol_bool_count(avc->handle, + avc->policydb, &cnt); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); + return 1; + } + + boollist = calloc(cnt, sizeof(*boollist)); + if (!boollist) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + return 1; + } + + sepol_bool_iterate(avc->handle, avc->policydb, + load_booleans, (void *)NULL); + + /* Initialize the sidtab for subsequent use by sepol_context_to_sid + and sepol_compute_av_reason. */ + rc = sepol_sidtab_init(&sidtab); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); + free(boollist); + return 1; + } + sepol_set_sidtab(&sidtab); + return 0; +} + +static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { + int result; + char *init_path=NULL; + if (avc) { + PyErr_SetString( PyExc_RuntimeError, "init called multiple times"); + return NULL; + } + if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) + return NULL; + result = __policy_init(init_path); + return Py_BuildValue("i", result); +} + +#define RETURN(X) \ + { \ + return Py_BuildValue("iO", (X), Py_None); \ + } + +static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { + char *reason_buf = NULL; + char * scon; + char * tcon; + char *tclassstr; + PyObject *listObj; + PyObject *strObj; + int numlines; + struct boolean_t *bools; + unsigned int reason; + sepol_security_id_t ssid, tsid; + sepol_security_class_t tclass; + sepol_access_vector_t perm, av; + struct sepol_av_decision avd; + int rc; + int i=0; + + if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) + return NULL; + + /* get the number of lines passed to us */ + numlines = PyList_Size(listObj); + + /* should raise an error here. */ + if (numlines < 0) return NULL; /* Not a list */ + + if (!avc) + RETURN(NOPOLICY) + + rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); + if (rc < 0) + RETURN(BADSCON) + + rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); + if (rc < 0) + RETURN(BADTCON) + + tclass = string_to_security_class(tclassstr); + if (!tclass) + RETURN(BADTCLASS) + + /* Convert the permission list to an AV. */ + av = 0; + + /* iterate over items of the list, grabbing strings, and parsing + for numbers */ + for (i=0; i<numlines; i++){ + char *permstr; + + /* grab the string object from the next element of the list */ + strObj = PyList_GetItem(listObj, i); /* Can't fail */ + + /* make it a string */ +#if PY_MAJOR_VERSION >= 3 + permstr = _PyUnicode_AsString( strObj ); +#else + permstr = PyString_AsString( strObj ); +#endif + + perm = string_to_av_perm(tclass, permstr); + if (!perm) + RETURN(BADPERM) + + av |= perm; + } + + /* Reproduce the computation. */ + rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0); + if (rc < 0) + RETURN(BADCOMPUTE) + + if (!reason) + RETURN(ALLOW) + + if (reason & SEPOL_COMPUTEAV_TE) { + avc->ssid = ssid; + avc->tsid = tsid; + avc->tclass = tclass; + avc->av = av; + if (check_booleans(&bools) == 0) { + if (av & ~avd.auditdeny) { + RETURN(DONTAUDIT) + } else { + RETURN(TERULE) + } + } else { + PyObject *outboollist; + struct boolean_t *b = bools; + int len=0; + while (b->name) { + len++; b++; + } + b = bools; + outboollist = PyList_New(len); + len=0; + while(b->name) { + PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); + PyList_SetItem(outboollist, len++, bool_); + b++; + } + free(bools); + /* 'N' steals the reference to outboollist */ + return Py_BuildValue("iN", BOOLEAN, outboollist); + } + } + + if (reason & SEPOL_COMPUTEAV_CONS) { + if (reason_buf) { + PyObject *result = NULL; + result = Py_BuildValue("is", CONSTRAINT, reason_buf); + free(reason_buf); + return result; + } + RETURN(CONSTRAINT) + } + + if (reason & SEPOL_COMPUTEAV_RBAC) + RETURN(RBAC) + + RETURN(BADCOMPUTE) +} + +static PyMethodDef audit2whyMethods[] = { + {"init", init, METH_VARARGS, + "Initialize policy database."}, + {"analyze", analyze, METH_VARARGS, + "Analyze AVC."}, + {"finish", finish, METH_VARARGS, + "Finish using policy, free memory."}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 +/* Module-initialization logic specific to Python 3 */ +struct module_state { + /* empty for now */ +}; +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "audit2why", + NULL, + sizeof(struct module_state), + audit2whyMethods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ +PyMODINIT_FUNC PyInit_audit2why(void) +#else +PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ +PyMODINIT_FUNC initaudit2why(void) +#endif +{ + PyObject *m; +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); + if (m == NULL) { + return NULL; + } +#else + m = Py_InitModule("audit2why", audit2whyMethods); +#endif + PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN); + PyModule_AddIntConstant(m,"BADSCON", BADSCON); + PyModule_AddIntConstant(m,"BADTCON", BADTCON); + PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS); + PyModule_AddIntConstant(m,"BADPERM", BADPERM); + PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE); + PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY); + PyModule_AddIntConstant(m,"ALLOW", ALLOW); + PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT); + PyModule_AddIntConstant(m,"TERULE", TERULE); + PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN); + PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT); + PyModule_AddIntConstant(m,"RBAC", RBAC); + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +}
diff --git a/selinux/libselinux/src/avc.c b/selinux/libselinux/src/avc.c new file mode 100644 index 0000000..b1ec57f --- /dev/null +++ b/selinux/libselinux/src/avc.c
@@ -0,0 +1,1176 @@ +/* + * Implementation of the userspace access vector cache (AVC). + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + * + * Derived from the kernel AVC implementation by + * Stephen Smalley <sds@epoch.ncsc.mil> and + * James Morris <jmorris@redhat.com>. + */ +#include <selinux/avc.h> +#include "selinux_internal.h" +#include <assert.h> +#include "avc_sidtab.h" +#include "avc_internal.h" + +#define AVC_CACHE_SLOTS 512 +#define AVC_CACHE_MAXNODES 410 + +struct avc_entry { + security_id_t ssid; + security_id_t tsid; + security_class_t tclass; + struct av_decision avd; + security_id_t create_sid; + int used; /* used recently */ +}; + +struct avc_node { + struct avc_entry ae; + struct avc_node *next; +}; + +struct avc_cache { + struct avc_node *slots[AVC_CACHE_SLOTS]; + uint32_t lru_hint; /* LRU hint for reclaim scan */ + uint32_t active_nodes; + uint32_t latest_notif; /* latest revocation notification */ +}; + +struct avc_callback_node { + int (*callback) (uint32_t event, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, access_vector_t perms, + access_vector_t * out_retained); + uint32_t events; + security_id_t ssid; + security_id_t tsid; + security_class_t tclass; + access_vector_t perms; + struct avc_callback_node *next; +}; + +static void *avc_netlink_thread = NULL; +static void *avc_lock = NULL; +static void *avc_log_lock = NULL; +static struct avc_node *avc_node_freelist = NULL; +static struct avc_cache avc_cache; +static char *avc_audit_buf = NULL; +static struct avc_cache_stats cache_stats; +static struct avc_callback_node *avc_callbacks = NULL; +static struct sidtab avc_sidtab; + +static inline int avc_hash(security_id_t ssid, + security_id_t tsid, security_class_t tclass) +{ + return ((uintptr_t) ssid ^ ((uintptr_t) tsid << 2) ^ tclass) + & (AVC_CACHE_SLOTS - 1); +} + +int avc_context_to_sid_raw(const char * ctx, security_id_t * sid) +{ + int rc; + /* avc_init needs to be called before this function */ + assert(avc_running); + + avc_get_lock(avc_lock); + rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid); + avc_release_lock(avc_lock); + return rc; +} + +int avc_context_to_sid(const char * ctx, security_id_t * sid) +{ + int ret; + char * rctx; + + if (selinux_trans_to_raw_context(ctx, &rctx)) + return -1; + + ret = avc_context_to_sid_raw(rctx, sid); + + freecon(rctx); + + return ret; +} + +int avc_sid_to_context_raw(security_id_t sid, char ** ctx) +{ + int rc; + *ctx = NULL; + avc_get_lock(avc_lock); + *ctx = strdup(sid->ctx); /* caller must free via freecon */ + rc = *ctx ? 0 : -1; + avc_release_lock(avc_lock); + return rc; +} + +int avc_sid_to_context(security_id_t sid, char ** ctx) +{ + int ret; + char * rctx; + + ret = avc_sid_to_context_raw(sid, &rctx); + + if (ret == 0) { + ret = selinux_raw_to_trans_context(rctx, ctx); + freecon(rctx); + } + + return ret; +} + +int sidget(security_id_t sid __attribute__((unused))) +{ + return 1; +} + +int sidput(security_id_t sid __attribute__((unused))) +{ + return 1; +} + +int avc_get_initial_sid(const char * name, security_id_t * sid) +{ + int rc; + char * con; + + rc = security_get_initial_context_raw(name, &con); + if (rc < 0) + return rc; + rc = avc_context_to_sid_raw(con, sid); + + freecon(con); + + return rc; +} + +int avc_open(struct selinux_opt *opts, unsigned nopts) +{ + avc_setenforce = 0; + + while (nopts--) + switch(opts[nopts].type) { + case AVC_OPT_SETENFORCE: + avc_setenforce = 1; + avc_enforcing = !!opts[nopts].value; + break; + } + + return avc_init("avc", NULL, NULL, NULL, NULL); +} + +int avc_init(const char *prefix, + const struct avc_memory_callback *mem_cb, + const struct avc_log_callback *log_cb, + const struct avc_thread_callback *thread_cb, + const struct avc_lock_callback *lock_cb) +{ + struct avc_node *new; + int i, rc = 0; + + if (avc_running) + return 0; + + if (prefix) + strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1); + + set_callbacks(mem_cb, log_cb, thread_cb, lock_cb); + + avc_lock = avc_alloc_lock(); + avc_log_lock = avc_alloc_lock(); + + memset(&cache_stats, 0, sizeof(cache_stats)); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) + avc_cache.slots[i] = 0; + avc_cache.lru_hint = 0; + avc_cache.active_nodes = 0; + avc_cache.latest_notif = 0; + + rc = sidtab_init(&avc_sidtab); + if (rc) { + avc_log(SELINUX_ERROR, + "%s: unable to initialize SID table\n", + avc_prefix); + goto out; + } + + avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE); + if (!avc_audit_buf) { + avc_log(SELINUX_ERROR, + "%s: unable to allocate audit buffer\n", + avc_prefix); + rc = -1; + goto out; + } + + for (i = 0; i < AVC_CACHE_MAXNODES; i++) { + new = avc_malloc(sizeof(*new)); + if (!new) { + avc_log(SELINUX_WARNING, + "%s: warning: only got %d av entries\n", + avc_prefix, i); + break; + } + memset(new, 0, sizeof(*new)); + new->next = avc_node_freelist; + avc_node_freelist = new; + } + + if (!avc_setenforce) { + rc = security_getenforce(); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: could not determine enforcing mode: %s\n", + avc_prefix, + strerror(errno)); + goto out; + } + avc_enforcing = rc; + } + + rc = avc_netlink_open(0); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: can't open netlink socket: %d (%s)\n", + avc_prefix, errno, strerror(errno)); + goto out; + } + if (avc_using_threads) { + avc_netlink_thread = avc_create_thread(&avc_netlink_loop); + avc_netlink_trouble = 0; + } + avc_running = 1; + out: + return rc; +} + +void avc_cache_stats(struct avc_cache_stats *p) +{ + memcpy(p, &cache_stats, sizeof(cache_stats)); +} + +void avc_sid_stats(void) +{ + /* avc_init needs to be called before this function */ + assert(avc_running); + avc_get_lock(avc_log_lock); + avc_get_lock(avc_lock); + sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE); + avc_release_lock(avc_lock); + avc_log(SELINUX_INFO, "%s", avc_audit_buf); + avc_release_lock(avc_log_lock); +} + +void avc_av_stats(void) +{ + int i, chain_len, max_chain_len, slots_used; + struct avc_node *node; + + avc_get_lock(avc_lock); + + slots_used = 0; + max_chain_len = 0; + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + if (node) { + slots_used++; + chain_len = 0; + while (node) { + chain_len++; + node = node->next; + } + if (chain_len > max_chain_len) + max_chain_len = chain_len; + } + } + + avc_release_lock(avc_lock); + + avc_log(SELINUX_INFO, "%s: %u AV entries and %d/%d buckets used, " + "longest chain length %d\n", avc_prefix, + avc_cache.active_nodes, + slots_used, AVC_CACHE_SLOTS, max_chain_len); +} + +hidden_def(avc_av_stats) + +static inline struct avc_node *avc_reclaim_node(void) +{ + struct avc_node *prev, *cur; + int try; + uint32_t hvalue; + + hvalue = avc_cache.lru_hint; + for (try = 0; try < 2; try++) { + do { + prev = NULL; + cur = avc_cache.slots[hvalue]; + while (cur) { + if (!cur->ae.used) + goto found; + + cur->ae.used = 0; + + prev = cur; + cur = cur->next; + } + hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1); + } while (hvalue != avc_cache.lru_hint); + } + + errno = ENOMEM; /* this was a panic in the kernel... */ + return NULL; + + found: + avc_cache.lru_hint = hvalue; + + if (prev == NULL) + avc_cache.slots[hvalue] = cur->next; + else + prev->next = cur->next; + + return cur; +} + +static inline void avc_clear_avc_entry(struct avc_entry *ae) +{ + memset(ae, 0, sizeof(*ae)); +} + +static inline struct avc_node *avc_claim_node(security_id_t ssid, + security_id_t tsid, + security_class_t tclass) +{ + struct avc_node *new; + int hvalue; + + if (!avc_node_freelist) + avc_cleanup(); + + if (avc_node_freelist) { + new = avc_node_freelist; + avc_node_freelist = avc_node_freelist->next; + avc_cache.active_nodes++; + } else { + new = avc_reclaim_node(); + if (!new) + goto out; + } + + hvalue = avc_hash(ssid, tsid, tclass); + avc_clear_avc_entry(&new->ae); + new->ae.used = 1; + new->ae.ssid = ssid; + new->ae.tsid = tsid; + new->ae.tclass = tclass; + new->next = avc_cache.slots[hvalue]; + avc_cache.slots[hvalue] = new; + + out: + return new; +} + +static inline struct avc_node *avc_search_node(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + int *probes) +{ + struct avc_node *cur; + int hvalue; + int tprobes = 1; + + hvalue = avc_hash(ssid, tsid, tclass); + cur = avc_cache.slots[hvalue]; + while (cur != NULL && + (ssid != cur->ae.ssid || + tclass != cur->ae.tclass || tsid != cur->ae.tsid)) { + tprobes++; + cur = cur->next; + } + + if (cur == NULL) { + /* cache miss */ + goto out; + } + + /* cache hit */ + if (probes) + *probes = tprobes; + + cur->ae.used = 1; + + out: + return cur; +} + +/** + * avc_lookup - Look up an AVC entry. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * + * Look up an AVC entry that is valid for the + * @requested permissions between the SID pair + * (@ssid, @tsid), interpreting the permissions + * based on @tclass. If a valid AVC entry exists, + * then this function updates @aeref to refer to the + * entry and returns %0. Otherwise, -1 is returned. + */ +static int avc_lookup(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t requested, struct avc_entry_ref *aeref) +{ + struct avc_node *node; + int probes, rc = 0; + + avc_cache_stats_incr(cav_lookups); + node = avc_search_node(ssid, tsid, tclass, &probes); + + if (node && ((node->ae.avd.decided & requested) == requested)) { + avc_cache_stats_incr(cav_hits); + avc_cache_stats_add(cav_probes, probes); + aeref->ae = &node->ae; + goto out; + } + + avc_cache_stats_incr(cav_misses); + rc = -1; + out: + return rc; +} + +/** + * avc_insert - Insert an AVC entry. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @ae: AVC entry + * @aeref: AVC entry reference + * + * Insert an AVC entry for the SID pair + * (@ssid, @tsid) and class @tclass. + * The access vectors and the sequence number are + * normally provided by the security server in + * response to a security_compute_av() call. If the + * sequence number @ae->avd.seqno is not less than the latest + * revocation notification, then the function copies + * the access vectors into a cache entry, updates + * @aeref to refer to the entry, and returns %0. + * Otherwise, this function returns -%1 with @errno set to %EAGAIN. + */ +static int avc_insert(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + struct avc_entry *ae, struct avc_entry_ref *aeref) +{ + struct avc_node *node; + int rc = 0; + + if (ae->avd.seqno < avc_cache.latest_notif) { + avc_log(SELINUX_WARNING, + "%s: seqno %u < latest_notif %u\n", avc_prefix, + ae->avd.seqno, avc_cache.latest_notif); + errno = EAGAIN; + rc = -1; + goto out; + } + + node = avc_claim_node(ssid, tsid, tclass); + if (!node) { + rc = -1; + goto out; + } + + memcpy(&node->ae.avd, &ae->avd, sizeof(ae->avd)); + aeref->ae = &node->ae; + out: + return rc; +} + +void avc_cleanup(void) +{ +} + +hidden_def(avc_cleanup) + +int avc_reset(void) +{ + struct avc_callback_node *c; + int i, ret, rc = 0, errsave = 0; + struct avc_node *node, *tmp; + errno = 0; + + if (!avc_running) + return 0; + + avc_get_lock(avc_lock); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + while (node) { + tmp = node; + node = node->next; + avc_clear_avc_entry(&tmp->ae); + tmp->next = avc_node_freelist; + avc_node_freelist = tmp; + avc_cache.active_nodes--; + } + avc_cache.slots[i] = 0; + } + avc_cache.lru_hint = 0; + + avc_release_lock(avc_lock); + + memset(&cache_stats, 0, sizeof(cache_stats)); + + for (c = avc_callbacks; c; c = c->next) { + if (c->events & AVC_CALLBACK_RESET) { + ret = c->callback(AVC_CALLBACK_RESET, 0, 0, 0, 0, 0); + if (ret && !rc) { + rc = ret; + errsave = errno; + } + } + } + errno = errsave; + return rc; +} + +hidden_def(avc_reset) + +void avc_destroy(void) +{ + struct avc_callback_node *c; + struct avc_node *node, *tmp; + int i; + /* avc_init needs to be called before this function */ + assert(avc_running); + + avc_get_lock(avc_lock); + + if (avc_using_threads) + avc_stop_thread(avc_netlink_thread); + avc_netlink_close(); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + while (node) { + tmp = node; + node = node->next; + avc_free(tmp); + } + } + while (avc_node_freelist) { + tmp = avc_node_freelist; + avc_node_freelist = tmp->next; + avc_free(tmp); + } + avc_release_lock(avc_lock); + + while (avc_callbacks) { + c = avc_callbacks; + avc_callbacks = c->next; + avc_free(c); + } + sidtab_destroy(&avc_sidtab); + avc_free_lock(avc_lock); + avc_free_lock(avc_log_lock); + avc_free(avc_audit_buf); + avc_running = 0; +} + +/* ratelimit stuff put aside for now --EFW */ +#if 0 +/* + * Copied from net/core/utils.c:net_ratelimit and modified for + * use by the AVC audit facility. + */ +#define AVC_MSG_COST 5*HZ +#define AVC_MSG_BURST 10*5*HZ + +/* + * This enforces a rate limit: not more than one kernel message + * every 5secs to make a denial-of-service attack impossible. + */ +static int avc_ratelimit(void) +{ + static unsigned long toks = 10 * 5 * HZ; + static unsigned long last_msg; + static int missed, rc = 0; + unsigned long now = jiffies; + void *ratelimit_lock = avc_alloc_lock(); + + avc_get_lock(ratelimit_lock); + toks += now - last_msg; + last_msg = now; + if (toks > AVC_MSG_BURST) + toks = AVC_MSG_BURST; + if (toks >= AVC_MSG_COST) { + int lost = missed; + missed = 0; + toks -= AVC_MSG_COST; + avc_release_lock(ratelimit_lock); + if (lost) { + avc_log(SELINUX_WARNING, + "%s: %d messages suppressed.\n", avc_prefix, + lost); + } + rc = 1; + goto out; + } + missed++; + avc_release_lock(ratelimit_lock); + out: + avc_free_lock(ratelimit_lock); + return rc; +} + +static inline int check_avc_ratelimit(void) +{ + if (avc_enforcing) + return avc_ratelimit(); + else { + /* If permissive, then never suppress messages. */ + return 1; + } +} +#endif /* ratelimit stuff */ + +/** + * avc_dump_av - Display an access vector in human-readable form. + * @tclass: target security class + * @av: access vector + */ +static void avc_dump_av(security_class_t tclass, access_vector_t av) +{ + const char *permstr; + access_vector_t bit = 1; + + if (av == 0) { + log_append(avc_audit_buf, " null"); + return; + } + + log_append(avc_audit_buf, " {"); + + while (av) { + if (av & bit) { + permstr = security_av_perm_to_string(tclass, bit); + if (!permstr) + break; + log_append(avc_audit_buf, " %s", permstr); + av &= ~bit; + } + bit <<= 1; + } + + if (av) + log_append(avc_audit_buf, " 0x%x", av); + log_append(avc_audit_buf, " }"); +} + +/** + * avc_dump_query - Display a SID pair and a class in human-readable form. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + */ +static void avc_dump_query(security_id_t ssid, security_id_t tsid, + security_class_t tclass) +{ + avc_get_lock(avc_lock); + + log_append(avc_audit_buf, "scontext=%s tcontext=%s", + ssid->ctx, tsid->ctx); + + avc_release_lock(avc_lock); + log_append(avc_audit_buf, " tclass=%s", + security_class_to_string(tclass)); +} + +void avc_audit(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct av_decision *avd, int result, void *a) +{ + access_vector_t denied, audited; + + denied = requested & ~avd->allowed; + if (denied) + audited = denied & avd->auditdeny; + else if (!requested || result) + audited = denied = requested; + else + audited = requested & avd->auditallow; + if (!audited) + return; +#if 0 + if (!check_avc_ratelimit()) + return; +#endif + /* prevent overlapping buffer writes */ + avc_get_lock(avc_log_lock); + snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE, + "%s: %s ", avc_prefix, (denied || !requested) ? "denied" : "granted"); + avc_dump_av(tclass, audited); + log_append(avc_audit_buf, " for "); + + /* get any extra information printed by the callback */ + avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf), + AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf)); + + log_append(avc_audit_buf, " "); + avc_dump_query(ssid, tsid, tclass); + log_append(avc_audit_buf, "\n"); + avc_log(SELINUX_AVC, "%s", avc_audit_buf); + + avc_release_lock(avc_log_lock); +} + +hidden_def(avc_audit) + + +static void avd_init(struct av_decision *avd) +{ + avd->allowed = 0; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = avc_cache.latest_notif; + avd->flags = 0; +} + +int avc_has_perm_noaudit(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, struct av_decision *avd) +{ + struct avc_entry *ae; + int rc = 0; + struct avc_entry entry; + access_vector_t denied; + struct avc_entry_ref ref; + + if (avd) + avd_init(avd); + + if (!avc_using_threads && !avc_app_main_loop) { + (void)avc_netlink_check_nb(); + } + + if (!aeref) { + avc_entry_ref_init(&ref); + aeref = &ref; + } + + avc_get_lock(avc_lock); + avc_cache_stats_incr(entry_lookups); + ae = aeref->ae; + if (ae) { + if (ae->ssid == ssid && + ae->tsid == tsid && + ae->tclass == tclass && + ((ae->avd.decided & requested) == requested)) { + avc_cache_stats_incr(entry_hits); + ae->used = 1; + } else { + avc_cache_stats_incr(entry_discards); + ae = 0; + } + } + + if (!ae) { + avc_cache_stats_incr(entry_misses); + rc = avc_lookup(ssid, tsid, tclass, requested, aeref); + if (rc) { + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, requested, + &entry.avd); + if (rc && errno == EINVAL && !avc_enforcing) { + rc = errno = 0; + goto out; + } + if (rc) + goto out; + rc = avc_insert(ssid, tsid, tclass, &entry, aeref); + if (rc) + goto out; + } + ae = aeref->ae; + } + + if (avd) + memcpy(avd, &ae->avd, sizeof(*avd)); + + denied = requested & ~(ae->avd.allowed); + + if (!requested || denied) { + if (!avc_enforcing || + (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)) + ae->avd.allowed |= requested; + else { + errno = EACCES; + rc = -1; + } + } + + out: + avc_release_lock(avc_lock); + return rc; +} + +hidden_def(avc_has_perm_noaudit) + +int avc_has_perm(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata) +{ + struct av_decision avd; + int errsave, rc; + + rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd); + errsave = errno; + avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); + errno = errsave; + return rc; +} + +int avc_compute_create(security_id_t ssid, security_id_t tsid, + security_class_t tclass, security_id_t *newsid) +{ + int rc; + struct avc_entry_ref aeref; + struct avc_entry entry; + char * ctx; + + *newsid = NULL; + avc_entry_ref_init(&aeref); + + avc_get_lock(avc_lock); + + /* check for a cached entry */ + rc = avc_lookup(ssid, tsid, tclass, 0, &aeref); + if (rc) { + /* need to make a cache entry for this tuple */ + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, 0, &entry.avd); + if (rc) + goto out; + rc = avc_insert(ssid, tsid, tclass, &entry, &aeref); + if (rc) + goto out; + } + + /* check for a saved compute_create value */ + if (!aeref.ae->create_sid) { + /* need to query the kernel policy */ + rc = security_compute_create_raw(ssid->ctx, tsid->ctx, tclass, + &ctx); + if (rc) + goto out; + rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid); + freecon(ctx); + if (rc) + goto out; + + aeref.ae->create_sid = *newsid; + } else { + /* found saved value */ + *newsid = aeref.ae->create_sid; + } + + rc = 0; +out: + avc_release_lock(avc_lock); + return rc; +} + +int avc_compute_member(security_id_t ssid, security_id_t tsid, + security_class_t tclass, security_id_t *newsid) +{ + int rc; + char * ctx = NULL; + *newsid = NULL; + /* avc_init needs to be called before this function */ + assert(avc_running); + avc_get_lock(avc_lock); + + rc = security_compute_member_raw(ssid->ctx, tsid->ctx, tclass, &ctx); + if (rc) + goto out; + rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid); + freecon(ctx); +out: + avc_release_lock(avc_lock); + return rc; +} + +int avc_add_callback(int (*callback) (uint32_t event, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t perms, + access_vector_t * out_retained), + uint32_t events, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, access_vector_t perms) +{ + struct avc_callback_node *c; + int rc = 0; + + c = avc_malloc(sizeof(*c)); + if (!c) { + rc = -1; + goto out; + } + + c->callback = callback; + c->events = events; + c->ssid = ssid; + c->tsid = tsid; + c->tclass = tclass; + c->perms = perms; + c->next = avc_callbacks; + avc_callbacks = c; + out: + return rc; +} + +static inline int avc_sidcmp(security_id_t x, security_id_t y) +{ + return (x == y || x == SECSID_WILD || y == SECSID_WILD); +} + +static inline void avc_update_node(uint32_t event, struct avc_node *node, + access_vector_t perms) +{ + switch (event) { + case AVC_CALLBACK_GRANT: + node->ae.avd.allowed |= perms; + break; + case AVC_CALLBACK_TRY_REVOKE: + case AVC_CALLBACK_REVOKE: + node->ae.avd.allowed &= ~perms; + break; + case AVC_CALLBACK_AUDITALLOW_ENABLE: + node->ae.avd.auditallow |= perms; + break; + case AVC_CALLBACK_AUDITALLOW_DISABLE: + node->ae.avd.auditallow &= ~perms; + break; + case AVC_CALLBACK_AUDITDENY_ENABLE: + node->ae.avd.auditdeny |= perms; + break; + case AVC_CALLBACK_AUDITDENY_DISABLE: + node->ae.avd.auditdeny &= ~perms; + break; + } +} + +static int avc_update_cache(uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms) +{ + struct avc_node *node; + int i; + + avc_get_lock(avc_lock); + + if (ssid == SECSID_WILD || tsid == SECSID_WILD) { + /* apply to all matching nodes */ + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + for (node = avc_cache.slots[i]; node; node = node->next) { + if (avc_sidcmp(ssid, node->ae.ssid) && + avc_sidcmp(tsid, node->ae.tsid) && + tclass == node->ae.tclass) { + avc_update_node(event, node, perms); + } + } + } + } else { + /* apply to one node */ + node = avc_search_node(ssid, tsid, tclass, 0); + if (node) { + avc_update_node(event, node, perms); + } + } + + avc_release_lock(avc_lock); + + return 0; +} + +/* avc_control - update cache and call callbacks + * + * This should not be called directly; use the individual event + * functions instead. + */ +static int avc_control(uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms, + uint32_t seqno, access_vector_t * out_retained) +{ + struct avc_callback_node *c; + access_vector_t tretained = 0, cretained = 0; + int ret, rc = 0, errsave = 0; + errno = 0; + + /* + * try_revoke only removes permissions from the cache + * state if they are not retained by the object manager. + * Hence, try_revoke must wait until after the callbacks have + * been invoked to update the cache state. + */ + if (event != AVC_CALLBACK_TRY_REVOKE) + avc_update_cache(event, ssid, tsid, tclass, perms); + + for (c = avc_callbacks; c; c = c->next) { + if ((c->events & event) && + avc_sidcmp(c->ssid, ssid) && + avc_sidcmp(c->tsid, tsid) && + c->tclass == tclass && (c->perms & perms)) { + cretained = 0; + ret = c->callback(event, ssid, tsid, tclass, + (c->perms & perms), &cretained); + if (ret && !rc) { + rc = ret; + errsave = errno; + } + if (!ret) + tretained |= cretained; + } + } + + if (event == AVC_CALLBACK_TRY_REVOKE) { + /* revoke any unretained permissions */ + perms &= ~tretained; + avc_update_cache(event, ssid, tsid, tclass, perms); + *out_retained = tretained; + } + + avc_get_lock(avc_lock); + if (seqno > avc_cache.latest_notif) + avc_cache.latest_notif = seqno; + avc_release_lock(avc_lock); + + errno = errsave; + return rc; +} + +/** + * avc_ss_grant - Grant previously denied permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + */ +int avc_ss_grant(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) +{ + return avc_control(AVC_CALLBACK_GRANT, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_try_revoke - Try to revoke previously granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @out_retained: subset of @perms that are retained + * + * Try to revoke previously granted permissions, but + * only if they are not retained as migrated permissions. + * Return the subset of permissions that are retained via @out_retained. + */ +int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t perms, uint32_t seqno, + access_vector_t * out_retained) +{ + return avc_control(AVC_CALLBACK_TRY_REVOKE, + ssid, tsid, tclass, perms, seqno, out_retained); +} + +/** + * avc_ss_revoke - Revoke previously granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * + * Revoke previously granted permissions, even if + * they are retained as migrated permissions. + */ +int avc_ss_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) +{ + return avc_control(AVC_CALLBACK_REVOKE, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_reset - Flush the cache and revalidate migrated permissions. + * @seqno: policy sequence number + */ +int avc_ss_reset(uint32_t seqno) +{ + int rc; + + rc = avc_reset(); + + avc_get_lock(avc_lock); + if (seqno > avc_cache.latest_notif) + avc_cache.latest_notif = seqno; + avc_release_lock(avc_lock); + + return rc; +} + +/** + * avc_ss_set_auditallow - Enable or disable auditing of granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @enable: enable flag. + */ +int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) +{ + if (enable) + return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE, + ssid, tsid, tclass, perms, seqno, 0); + else + return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @enable: enable flag. + */ +int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) +{ + if (enable) + return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE, + ssid, tsid, tclass, perms, seqno, 0); + else + return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE, + ssid, tsid, tclass, perms, seqno, 0); +}
diff --git a/selinux/libselinux/src/avc_internal.c b/selinux/libselinux/src/avc_internal.c new file mode 100644 index 0000000..be94857 --- /dev/null +++ b/selinux/libselinux/src/avc_internal.c
@@ -0,0 +1,292 @@ +/* + * Callbacks for user-supplied memory allocation, supplemental + * auditing, and locking routines. + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + * + * Netlink code derived in part from sample code by + * James Morris <jmorris@redhat.com>. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <linux/types.h> +#include <linux/netlink.h> +#include "callbacks.h" +#include "selinux_netlink.h" +#include "avc_internal.h" + +#ifndef NETLINK_SELINUX +#define NETLINK_SELINUX 7 +#endif + +/* callback pointers */ +void *(*avc_func_malloc) (size_t) = NULL; +void (*avc_func_free) (void *) = NULL; + +void (*avc_func_log) (const char *, ...) = NULL; +void (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL; + +int avc_using_threads = 0; +int avc_app_main_loop = 0; +void *(*avc_func_create_thread) (void (*)(void)) = NULL; +void (*avc_func_stop_thread) (void *) = NULL; + +void *(*avc_func_alloc_lock) (void) = NULL; +void (*avc_func_get_lock) (void *) = NULL; +void (*avc_func_release_lock) (void *) = NULL; +void (*avc_func_free_lock) (void *) = NULL; + +/* message prefix string and avc enforcing mode */ +char avc_prefix[AVC_PREFIX_SIZE] = "uavc"; +int avc_running = 0; +int avc_enforcing = 1; +int avc_setenforce = 0; +int avc_netlink_trouble = 0; + +/* netlink socket code */ +static int fd = -1; + +int avc_netlink_open(int blocking) +{ + int len, rc = 0; + struct sockaddr_nl addr; + + fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_SELINUX); + if (fd < 0) { + rc = fd; + goto out; + } + + if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) { + close(fd); + fd = -1; + rc = -1; + goto out; + } + + len = sizeof(addr); + + memset(&addr, 0, len); + addr.nl_family = AF_NETLINK; + addr.nl_groups = SELNL_GRP_AVC; + + if (bind(fd, (struct sockaddr *)&addr, len) < 0) { + close(fd); + fd = -1; + rc = -1; + goto out; + } + out: + return rc; +} + +void avc_netlink_close(void) +{ + if (fd >= 0) + close(fd); + fd = -1; +} + +static int avc_netlink_receive(char *buf, unsigned buflen, int blocking) +{ + int rc; + struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 }; + struct sockaddr_nl nladdr; + socklen_t nladdrlen = sizeof nladdr; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + do { + rc = poll(&pfd, 1, (blocking ? -1 : 0)); + } while (rc < 0 && errno == EINTR); + + if (rc == 0 && !blocking) { + errno = EWOULDBLOCK; + return -1; + } + else if (rc < 1) { + avc_log(SELINUX_ERROR, "%s: netlink poll: error %d\n", + avc_prefix, errno); + return rc; + } + + rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr, + &nladdrlen); + if (rc < 0) + return rc; + + if (nladdrlen != sizeof nladdr) { + avc_log(SELINUX_WARNING, + "%s: warning: netlink address truncated, len %u?\n", + avc_prefix, nladdrlen); + return -1; + } + + if (nladdr.nl_pid) { + avc_log(SELINUX_WARNING, + "%s: warning: received spoofed netlink packet from: %u\n", + avc_prefix, nladdr.nl_pid); + return -1; + } + + if (rc == 0) { + avc_log(SELINUX_WARNING, + "%s: warning: received EOF on netlink socket\n", + avc_prefix); + errno = EBADFD; + return -1; + } + + if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) { + avc_log(SELINUX_WARNING, + "%s: warning: incomplete netlink message\n", + avc_prefix); + return -1; + } + + return 0; +} + +static int avc_netlink_process(char *buf) +{ + int rc; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + switch (nlh->nlmsg_type) { + case NLMSG_ERROR:{ + struct nlmsgerr *err = NLMSG_DATA(nlh); + + /* Netlink ack */ + if (err->error == 0) + break; + + errno = -err->error; + avc_log(SELINUX_ERROR, + "%s: netlink error: %d\n", avc_prefix, errno); + return -1; + } + + case SELNL_MSG_SETENFORCE:{ + struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh); + avc_log(SELINUX_INFO, + "%s: received setenforce notice (enforcing=%d)\n", + avc_prefix, msg->val); + if (avc_setenforce) + break; + avc_enforcing = msg->val; + if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) { + avc_log(SELINUX_ERROR, + "%s: cache reset returned %d (errno %d)\n", + avc_prefix, rc, errno); + return rc; + } + rc = selinux_netlink_setenforce(msg->val); + if (rc < 0) + return rc; + break; + } + + case SELNL_MSG_POLICYLOAD:{ + struct selnl_msg_policyload *msg = NLMSG_DATA(nlh); + avc_log(SELINUX_INFO, + "%s: received policyload notice (seqno=%u)\n", + avc_prefix, msg->seqno); + rc = avc_ss_reset(msg->seqno); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: cache reset returned %d (errno %d)\n", + avc_prefix, rc, errno); + return rc; + } + rc = selinux_netlink_policyload(msg->seqno); + if (rc < 0) + return rc; + break; + } + + default: + avc_log(SELINUX_WARNING, + "%s: warning: unknown netlink message %d\n", + avc_prefix, nlh->nlmsg_type); + } + return 0; +} + +int avc_netlink_check_nb(void) +{ + int rc; + char buf[1024] __attribute__ ((aligned)); + + while (1) { + errno = 0; + rc = avc_netlink_receive(buf, sizeof(buf), 0); + if (rc < 0) { + if (errno == EWOULDBLOCK) + return 0; + if (errno == 0 || errno == EINTR) + continue; + else { + avc_log(SELINUX_ERROR, + "%s: netlink recvfrom: error %d\n", + avc_prefix, errno); + return rc; + } + } + + (void)avc_netlink_process(buf); + } + return 0; +} + +/* run routine for the netlink listening thread */ +void avc_netlink_loop(void) +{ + int rc; + char buf[1024] __attribute__ ((aligned)); + + while (1) { + errno = 0; + rc = avc_netlink_receive(buf, sizeof(buf), 1); + if (rc < 0) { + if (errno == 0 || errno == EINTR) + continue; + else { + avc_log(SELINUX_ERROR, + "%s: netlink recvfrom: error %d\n", + avc_prefix, errno); + break; + } + } + + rc = avc_netlink_process(buf); + if (rc < 0) + break; + } + + close(fd); + fd = -1; + avc_netlink_trouble = 1; + avc_log(SELINUX_ERROR, + "%s: netlink thread: errors encountered, terminating\n", + avc_prefix); +} + +int avc_netlink_acquire_fd(void) +{ + avc_app_main_loop = 1; + + return fd; +} + +void avc_netlink_release_fd(void) +{ + avc_app_main_loop = 0; +}
diff --git a/selinux/libselinux/src/avc_internal.h b/selinux/libselinux/src/avc_internal.h new file mode 100644 index 0000000..f851659 --- /dev/null +++ b/selinux/libselinux/src/avc_internal.h
@@ -0,0 +1,182 @@ +/* + * This file describes the internal interface used by the AVC + * for calling the user-supplied memory allocation, supplemental + * auditing, and locking routine, as well as incrementing the + * statistics fields. + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + */ +#ifndef _SELINUX_AVC_INTERNAL_H_ +#define _SELINUX_AVC_INTERNAL_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <selinux/avc.h> +#include "callbacks.h" +#include "dso.h" + +/* callback pointers */ +extern void *(*avc_func_malloc) (size_t) hidden; +extern void (*avc_func_free) (void *)hidden; + +extern void (*avc_func_log) (const char *, ...) __attribute__((__format__(printf,1,2))) hidden; +extern void (*avc_func_audit) (void *, security_class_t, char *, size_t)hidden; + +extern int avc_using_threads hidden; +extern int avc_app_main_loop hidden; +extern void *(*avc_func_create_thread) (void (*)(void))hidden; +extern void (*avc_func_stop_thread) (void *)hidden; + +extern void *(*avc_func_alloc_lock) (void)hidden; +extern void (*avc_func_get_lock) (void *)hidden; +extern void (*avc_func_release_lock) (void *)hidden; +extern void (*avc_func_free_lock) (void *)hidden; + +static inline void set_callbacks(const struct avc_memory_callback *mem_cb, + const struct avc_log_callback *log_cb, + const struct avc_thread_callback *thread_cb, + const struct avc_lock_callback *lock_cb) +{ + if (mem_cb) { + avc_func_malloc = mem_cb->func_malloc; + avc_func_free = mem_cb->func_free; + } + if (log_cb) { + avc_func_log = log_cb->func_log; + avc_func_audit = log_cb->func_audit; + } + if (thread_cb) { + avc_using_threads = 1; + avc_func_create_thread = thread_cb->func_create_thread; + avc_func_stop_thread = thread_cb->func_stop_thread; + } + if (lock_cb) { + avc_func_alloc_lock = lock_cb->func_alloc_lock; + avc_func_get_lock = lock_cb->func_get_lock; + avc_func_release_lock = lock_cb->func_release_lock; + avc_func_free_lock = lock_cb->func_free_lock; + } +} + +/* message prefix and enforcing mode*/ +#define AVC_PREFIX_SIZE 16 +extern char avc_prefix[AVC_PREFIX_SIZE] hidden; +extern int avc_running hidden; +extern int avc_enforcing hidden; +extern int avc_setenforce hidden; + +/* user-supplied callback interface for avc */ +static inline void *avc_malloc(size_t size) +{ + return avc_func_malloc ? avc_func_malloc(size) : malloc(size); +} + +static inline void avc_free(void *ptr) +{ + if (avc_func_free) + avc_func_free(ptr); + else + free(ptr); +} + +/* this is a macro in order to use the variadic capability. */ +#define avc_log(type, format...) \ + if (avc_func_log) \ + avc_func_log(format); \ + else \ + selinux_log(type, format); + +static inline void avc_suppl_audit(void *ptr, security_class_t class, + char *buf, size_t len) +{ + if (avc_func_audit) + avc_func_audit(ptr, class, buf, len); + else + selinux_audit(ptr, class, buf, len); +} + +static inline void *avc_create_thread(void (*run) (void)) +{ + return avc_func_create_thread ? avc_func_create_thread(run) : NULL; +} + +static inline void avc_stop_thread(void *thread) +{ + if (avc_func_stop_thread) + avc_func_stop_thread(thread); +} + +static inline void *avc_alloc_lock(void) +{ + return avc_func_alloc_lock ? avc_func_alloc_lock() : NULL; +} + +static inline void avc_get_lock(void *lock) +{ + if (avc_func_get_lock) + avc_func_get_lock(lock); +} + +static inline void avc_release_lock(void *lock) +{ + if (avc_func_release_lock) + avc_func_release_lock(lock); +} + +static inline void avc_free_lock(void *lock) +{ + if (avc_func_free_lock) + avc_func_free_lock(lock); +} + +/* statistics helper routines */ +#ifdef AVC_CACHE_STATS + +#define avc_cache_stats_incr(field) \ + cache_stats.field ++; +#define avc_cache_stats_add(field, num) \ + cache_stats.field += num; + +#else + +#define avc_cache_stats_incr(field) +#define avc_cache_stats_add(field, num) + +#endif + +/* logging helper routines */ +#define AVC_AUDIT_BUFSIZE 1024 + +/* again, we need the variadic capability here */ +#define log_append(buf,format...) \ + snprintf(buf+strlen(buf), AVC_AUDIT_BUFSIZE-strlen(buf), format) + +/* internal callbacks */ +int avc_ss_grant(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) hidden; +int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t perms, uint32_t seqno, + access_vector_t * out_retained) hidden; +int avc_ss_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) hidden; +int avc_ss_reset(uint32_t seqno) hidden; +int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) hidden; +int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) hidden; + +/* netlink kernel message code */ +extern int avc_netlink_trouble hidden; + +hidden_proto(avc_av_stats) + hidden_proto(avc_cleanup) + hidden_proto(avc_reset) + hidden_proto(avc_audit) + hidden_proto(avc_has_perm_noaudit) +#endif /* _SELINUX_AVC_INTERNAL_H_ */
diff --git a/selinux/libselinux/src/avc_sidtab.c b/selinux/libselinux/src/avc_sidtab.c new file mode 100644 index 0000000..9669264 --- /dev/null +++ b/selinux/libselinux/src/avc_sidtab.c
@@ -0,0 +1,152 @@ +/* + * Implementation of the userspace SID hashtable. + * + * Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil> + */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "selinux_internal.h" +#include <selinux/avc.h> +#include "avc_sidtab.h" +#include "avc_internal.h" + +static inline unsigned sidtab_hash(const char * key) +{ + char *p, *keyp; + unsigned int size; + unsigned int val; + + val = 0; + keyp = (char *)key; + size = strlen(keyp); + for (p = keyp; (unsigned int)(p - keyp) < size; p++) + val = + (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); + return val & (SIDTAB_SIZE - 1); +} + +int sidtab_init(struct sidtab *s) +{ + int i, rc = 0; + + s->htable = (struct sidtab_node **)avc_malloc + (sizeof(struct sidtab_node *) * SIDTAB_SIZE); + + if (!s->htable) { + rc = -1; + goto out; + } + for (i = 0; i < SIDTAB_SIZE; i++) + s->htable[i] = NULL; + s->nel = 0; + out: + return rc; +} + +int sidtab_insert(struct sidtab *s, const char * ctx) +{ + int hvalue, rc = 0; + struct sidtab_node *newnode; + char * newctx; + + newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode)); + if (!newnode) { + rc = -1; + goto out; + } + newctx = (char *) strdup(ctx); + if (!newctx) { + rc = -1; + avc_free(newnode); + goto out; + } + + hvalue = sidtab_hash(newctx); + newnode->next = s->htable[hvalue]; + newnode->sid_s.ctx = newctx; + newnode->sid_s.refcnt = 1; /* unused */ + s->htable[hvalue] = newnode; + s->nel++; + out: + return rc; +} + +int +sidtab_context_to_sid(struct sidtab *s, + const char * ctx, security_id_t * sid) +{ + int hvalue, rc = 0; + struct sidtab_node *cur; + + *sid = NULL; + hvalue = sidtab_hash(ctx); + + loop: + cur = s->htable[hvalue]; + while (cur != NULL && strcmp(cur->sid_s.ctx, ctx)) + cur = cur->next; + + if (cur == NULL) { /* need to make a new entry */ + rc = sidtab_insert(s, ctx); + if (rc) + goto out; + goto loop; /* find the newly inserted node */ + } + + *sid = &cur->sid_s; + out: + return rc; +} + +void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen) +{ + int i, chain_len, slots_used, max_chain_len; + struct sidtab_node *cur; + + slots_used = 0; + max_chain_len = 0; + for (i = 0; i < SIDTAB_SIZE; i++) { + cur = h->htable[i]; + if (cur) { + slots_used++; + chain_len = 0; + while (cur) { + chain_len++; + cur = cur->next; + } + + if (chain_len > max_chain_len) + max_chain_len = chain_len; + } + } + + snprintf(buf, buflen, + "%s: %u SID entries and %d/%d buckets used, longest " + "chain length %d\n", avc_prefix, h->nel, slots_used, + SIDTAB_SIZE, max_chain_len); +} + +void sidtab_destroy(struct sidtab *s) +{ + int i; + struct sidtab_node *cur, *temp; + + if (!s) + return; + + for (i = 0; i < SIDTAB_SIZE; i++) { + cur = s->htable[i]; + while (cur != NULL) { + temp = cur; + cur = cur->next; + freecon(temp->sid_s.ctx); + avc_free(temp); + } + s->htable[i] = NULL; + } + avc_free(s->htable); + s->htable = NULL; +}
diff --git a/selinux/libselinux/src/avc_sidtab.h b/selinux/libselinux/src/avc_sidtab.h new file mode 100644 index 0000000..bce9b87 --- /dev/null +++ b/selinux/libselinux/src/avc_sidtab.h
@@ -0,0 +1,36 @@ +/* + * A security identifier table (sidtab) is a hash table + * of security context structures indexed by SID value. + */ +#ifndef _SELINUX_AVC_SIDTAB_H_ +#define _SELINUX_AVC_SIDTAB_H_ + +#include <selinux/selinux.h> +#include <selinux/avc.h> +#include "dso.h" + +struct sidtab_node { + struct security_id sid_s; + struct sidtab_node *next; +}; + +#define SIDTAB_HASH_BITS 7 +#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) +#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) +#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS + +struct sidtab { + struct sidtab_node **htable; + unsigned nel; +}; + +int sidtab_init(struct sidtab *s) hidden; +int sidtab_insert(struct sidtab *s, const char * ctx) hidden; + +int sidtab_context_to_sid(struct sidtab *s, + const char * ctx, security_id_t * sid) hidden; + +void sidtab_sid_stats(struct sidtab *s, char *buf, int buflen) hidden; +void sidtab_destroy(struct sidtab *s) hidden; + +#endif /* _SELINUX_AVC_SIDTAB_H_ */
diff --git a/selinux/libselinux/src/booleans.c b/selinux/libselinux/src/booleans.c new file mode 100644 index 0000000..4b39a28 --- /dev/null +++ b/selinux/libselinux/src/booleans.c
@@ -0,0 +1,570 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * Modified: + * Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans(). + */ + +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <dirent.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <unistd.h> +#include <fnmatch.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> + +#include "selinux_internal.h" +#include "policy.h" + +#define SELINUX_BOOL_DIR "/booleans/" + +static int filename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + return 0; + return 1; +} + +int security_get_boolean_names(char ***names, int *len) +{ + char path[PATH_MAX]; + int i, rc; + struct dirent **namelist; + char **n; + + if (!len || names == NULL) { + errno = EINVAL; + return -1; + } + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR); + *len = scandir(path, &namelist, &filename_select, alphasort); + if (*len <= 0) { + return -1; + } + + n = (char **)malloc(sizeof(char *) * *len); + if (!n) { + rc = -1; + goto bad; + } + + for (i = 0; i < *len; i++) { + n[i] = (char *)malloc(_D_ALLOC_NAMLEN(namelist[i])); + if (!n[i]) { + rc = -1; + goto bad_freen; + } + strcpy(n[i], namelist[i]->d_name); + } + rc = 0; + *names = n; + out: + for (i = 0; i < *len; i++) { + free(namelist[i]); + } + free(namelist); + return rc; + bad_freen: + for (--i; i >= 0; --i) + free(n[i]); + free(n); + bad: + goto out; +} + +hidden_def(security_get_boolean_names) + +char *selinux_boolean_sub(const char *name) +{ + char *sub = NULL; + char *line_buf = NULL; + size_t line_len; + FILE *cfg; + + if (!name) + return NULL; + + cfg = fopen(selinux_booleans_subs_path(), "r"); + if (!cfg) + goto out; + + while (getline(&line_buf, &line_len, cfg) != -1) { + char *ptr; + char *src = line_buf; + char *dst; + while (*src && isspace(*src)) + src++; + if (!*src) + continue; + if (src[0] == '#') + continue; + + ptr = src; + while (*ptr && !isspace(*ptr)) + ptr++; + *ptr++ = '\0'; + if (strcmp(src, name) != 0) + continue; + + dst = ptr; + while (*dst && isspace(*dst)) + dst++; + if (!*dst) + continue; + ptr=dst; + while (*ptr && !isspace(*ptr)) + ptr++; + *ptr='\0'; + + sub = strdup(dst); + + break; + } + free(line_buf); + fclose(cfg); +out: + if (!sub) + sub = strdup(name); + return sub; +} + +hidden_def(selinux_boolean_sub) + +static int bool_open(const char *name, int flag) { + char *fname = NULL; + char *alt_name = NULL; + int len; + int fd = -1; + int ret; + char *ptr; + + if (!name) { + errno = EINVAL; + return -1; + } + + /* note the 'sizeof' gets us enough room for the '\0' */ + len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); + fname = malloc(sizeof(char) * len); + if (!fname) + return -1; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); + if (ret < 0) + goto out; + assert(ret < len); + + fd = open(fname, flag); + if (fd >= 0 || errno != ENOENT) + goto out; + + alt_name = selinux_boolean_sub(name); + if (!alt_name) + goto out; + + /* note the 'sizeof' gets us enough room for the '\0' */ + len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); + ptr = realloc(fname, len); + if (!ptr) + goto out; + fname = ptr; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); + if (ret < 0) + goto out; + assert(ret < len); + + fd = open(fname, flag); +out: + free(fname); + free(alt_name); + + return fd; +} + +#define STRBUF_SIZE 3 +static int get_bool_value(const char *name, char **buf) +{ + int fd, len; + int errno_tmp; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1)); + if (!*buf) + return -1; + + (*buf)[STRBUF_SIZE] = 0; + + fd = bool_open(name, O_RDONLY); + if (fd < 0) + goto out_err; + + len = read(fd, *buf, STRBUF_SIZE); + errno_tmp = errno; + close(fd); + errno = errno_tmp; + if (len != STRBUF_SIZE) + goto out_err; + + return 0; +out_err: + free(*buf); + return -1; +} + +int security_get_boolean_pending(const char *name) +{ + char *buf; + int val; + + if (get_bool_value(name, &buf)) + return -1; + + if (atoi(&buf[1])) + val = 1; + else + val = 0; + free(buf); + return val; +} + +int security_get_boolean_active(const char *name) +{ + char *buf; + int val; + + if (get_bool_value(name, &buf)) + return -1; + + buf[1] = '\0'; + if (atoi(buf)) + val = 1; + else + val = 0; + free(buf); + return val; +} + +hidden_def(security_get_boolean_active) + +int security_set_boolean(const char *name, int value) +{ + int fd, ret; + char buf[2]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + if (value < 0 || value > 1) { + errno = EINVAL; + return -1; + } + + fd = bool_open(name, O_WRONLY); + if (fd < 0) + return -1; + + if (value) + buf[0] = '1'; + else + buf[0] = '0'; + buf[1] = '\0'; + + ret = write(fd, buf, 2); + close(fd); + + if (ret > 0) + return 0; + else + return -1; +} + +hidden_def(security_set_boolean) + +int security_commit_booleans(void) +{ + int fd, ret; + char buf[2]; + char path[PATH_MAX]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt); + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + buf[0] = '1'; + buf[1] = '\0'; + + ret = write(fd, buf, 2); + close(fd); + + if (ret > 0) + return 0; + else + return -1; +} + +hidden_def(security_commit_booleans) + +static char *strtrim(char *dest, char *source, int size) +{ + int i = 0; + char *ptr = source; + i = 0; + while (isspace(*ptr) && i < size) { + ptr++; + i++; + } + strncpy(dest, ptr, size); + for (i = strlen(dest) - 1; i > 0; i--) { + if (!isspace(dest[i])) + break; + } + dest[i + 1] = '\0'; + return dest; +} +static int process_boolean(char *buffer, char *name, int namesize, int *val) +{ + char name1[BUFSIZ]; + char *ptr = NULL; + char *tok = strtok_r(buffer, "=", &ptr); + if (tok) { + strncpy(name1, tok, BUFSIZ - 1); + strtrim(name, name1, namesize - 1); + if (name[0] == '#') + return 0; + tok = strtok_r(NULL, "\0", &ptr); + if (tok) { + while (isspace(*tok)) + tok++; + *val = -1; + if (isdigit(tok[0])) + *val = atoi(tok); + else if (!strncasecmp(tok, "true", sizeof("true") - 1)) + *val = 1; + else if (!strncasecmp + (tok, "false", sizeof("false") - 1)) + *val = 0; + if (*val != 0 && *val != 1) { + errno = EINVAL; + return -1; + } + + } + } + return 1; +} +static int save_booleans(size_t boolcnt, SELboolean * boollist) +{ + ssize_t len; + size_t i; + char outbuf[BUFSIZ]; + char *inbuf = NULL; + + /* Open file */ + const char *bool_file = selinux_booleans_path(); + char local_bool_file[PATH_MAX]; + char tmp_bool_file[PATH_MAX]; + FILE *boolf; + int fd; + int *used = (int *)malloc(sizeof(int) * boolcnt); + if (!used) { + return -1; + } + /* zero out used field */ + for (i = 0; i < boolcnt; i++) + used[i] = 0; + + snprintf(tmp_bool_file, sizeof(tmp_bool_file), "%s.XXXXXX", bool_file); + fd = mkstemp(tmp_bool_file); + if (fd < 0) { + free(used); + return -1; + } + + snprintf(local_bool_file, sizeof(local_bool_file), "%s.local", + bool_file); + boolf = fopen(local_bool_file, "r"); + if (boolf != NULL) { + ssize_t ret; + size_t size = 0; + int val; + char boolname[BUFSIZ]; + char *buffer; + inbuf = NULL; + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while ((len = getline(&inbuf, &size, boolf)) > 0) { + buffer = strdup(inbuf); + if (!buffer) + goto close_remove_fail; + ret = + process_boolean(inbuf, boolname, sizeof(boolname), + &val); + if (ret != 1) { + ret = write(fd, buffer, len); + free(buffer); + if (ret != len) + goto close_remove_fail; + } else { + free(buffer); + for (i = 0; i < boolcnt; i++) { + if (strcmp(boollist[i].name, boolname) + == 0) { + snprintf(outbuf, sizeof(outbuf), + "%s=%d\n", boolname, + boollist[i].value); + len = strlen(outbuf); + used[i] = 1; + if (write(fd, outbuf, len) != + len) + goto close_remove_fail; + else + break; + } + } + if (i == boolcnt) { + snprintf(outbuf, sizeof(outbuf), + "%s=%d\n", boolname, val); + len = strlen(outbuf); + if (write(fd, outbuf, len) != len) + goto close_remove_fail; + } + } + free(inbuf); + inbuf = NULL; + } + fclose(boolf); + } + + for (i = 0; i < boolcnt; i++) { + if (used[i] == 0) { + snprintf(outbuf, sizeof(outbuf), "%s=%d\n", + boollist[i].name, boollist[i].value); + len = strlen(outbuf); + if (write(fd, outbuf, len) != len) { + close_remove_fail: + free(inbuf); + close(fd); + remove_fail: + unlink(tmp_bool_file); + free(used); + return -1; + } + } + + } + if (fchmod(fd, S_IRUSR | S_IWUSR) != 0) + goto close_remove_fail; + close(fd); + if (rename(tmp_bool_file, local_bool_file) != 0) + goto remove_fail; + + free(used); + return 0; +} +static void rollback(SELboolean * boollist, int end) +{ + int i; + + for (i = 0; i < end; i++) + security_set_boolean(boollist[i].name, + security_get_boolean_active(boollist[i]. + name)); +} + +int security_set_boolean_list(size_t boolcnt, SELboolean * boollist, + int permanent) +{ + + size_t i; + for (i = 0; i < boolcnt; i++) { + if (security_set_boolean(boollist[i].name, boollist[i].value)) { + rollback(boollist, i); + return -1; + } + } + + /* OK, let's do the commit */ + if (security_commit_booleans()) { + return -1; + } + + if (permanent) + return save_booleans(boolcnt, boollist); + + return 0; +} +int security_load_booleans(char *path) +{ + FILE *boolf; + char *inbuf; + char localbools[BUFSIZ]; + size_t len = 0, errors = 0; + int val; + char name[BUFSIZ]; + + boolf = fopen(path ? path : selinux_booleans_path(), "r"); + if (boolf == NULL) + goto localbool; + + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while (getline(&inbuf, &len, boolf) > 0) { + int ret = process_boolean(inbuf, name, sizeof(name), &val); + if (ret == -1) + errors++; + if (ret == 1) + if (security_set_boolean(name, val) < 0) { + errors++; + } + } + fclose(boolf); + localbool: + snprintf(localbools, sizeof(localbools), "%s.local", + (path ? path : selinux_booleans_path())); + boolf = fopen(localbools, "r"); + + if (boolf != NULL) { + int ret; + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while (getline(&inbuf, &len, boolf) > 0) { + ret = process_boolean(inbuf, name, sizeof(name), &val); + if (ret == -1) + errors++; + if (ret == 1) + if (security_set_boolean(name, val) < 0) { + errors++; + } + } + fclose(boolf); + } + if (security_commit_booleans() < 0) + return -1; + + if (errors) + errno = EINVAL; + return errors ? -1 : 0; +}
diff --git a/selinux/libselinux/src/callbacks.c b/selinux/libselinux/src/callbacks.c new file mode 100644 index 0000000..cdf7b63 --- /dev/null +++ b/selinux/libselinux/src/callbacks.c
@@ -0,0 +1,125 @@ +/* + * User-supplied callbacks and default implementations. + * Class and permission mappings. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#include <selinux/selinux.h> +#include "callbacks.h" + +/* default implementations */ +static int __attribute__ ((format(printf, 2, 3))) +default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) +{ + int rc; + va_list ap; + if (is_selinux_enabled() == 0) return 0; + va_start(ap, fmt); + rc = vfprintf(stderr, fmt, ap); + va_end(ap); + return rc; +} + +static int +default_selinux_audit(void *ptr __attribute__((unused)), + security_class_t cls __attribute__((unused)), + char *buf __attribute__((unused)), + size_t len __attribute__((unused))) +{ + return 0; +} + +static int +default_selinux_validate(char **ctx) +{ + return security_check_context(*ctx); +} + +static int +default_selinux_setenforce(int enforcing __attribute__((unused))) +{ + return 0; +} + +static int +default_selinux_policyload(int seqno __attribute__((unused))) +{ + return 0; +} + +/* callback pointers */ +int __attribute__ ((format(printf, 2, 3))) +(*selinux_log)(int, const char *, ...) = + default_selinux_log; + +int +(*selinux_audit) (void *, security_class_t, char *, size_t) = + default_selinux_audit; + +int +(*selinux_validate)(char **ctx) = + default_selinux_validate; + +int +(*selinux_netlink_setenforce) (int enforcing) = + default_selinux_setenforce; + +int +(*selinux_netlink_policyload) (int seqno) = + default_selinux_policyload; + +/* callback setting function */ +void +selinux_set_callback(int type, union selinux_callback cb) +{ + switch (type) { + case SELINUX_CB_LOG: + selinux_log = cb.func_log; + break; + case SELINUX_CB_AUDIT: + selinux_audit = cb.func_audit; + break; + case SELINUX_CB_VALIDATE: + selinux_validate = cb.func_validate; + break; + case SELINUX_CB_SETENFORCE: + selinux_netlink_setenforce = cb.func_setenforce; + break; + case SELINUX_CB_POLICYLOAD: + selinux_netlink_policyload = cb.func_policyload; + break; + } +} + +/* callback getting function */ +union selinux_callback +selinux_get_callback(int type) +{ + union selinux_callback cb; + + switch (type) { + case SELINUX_CB_LOG: + cb.func_log = selinux_log; + break; + case SELINUX_CB_AUDIT: + cb.func_audit = selinux_audit; + break; + case SELINUX_CB_VALIDATE: + cb.func_validate = selinux_validate; + break; + case SELINUX_CB_SETENFORCE: + cb.func_setenforce = selinux_netlink_setenforce; + break; + case SELINUX_CB_POLICYLOAD: + cb.func_policyload = selinux_netlink_policyload; + break; + default: + memset(&cb, 0, sizeof(cb)); + errno = EINVAL; + break; + } + return cb; +}
diff --git a/selinux/libselinux/src/callbacks.h b/selinux/libselinux/src/callbacks.h new file mode 100644 index 0000000..2a572e0 --- /dev/null +++ b/selinux/libselinux/src/callbacks.h
@@ -0,0 +1,30 @@ +/* + * This file describes the callbacks passed to selinux_init() and available + * for use from the library code. They all have default implementations. + */ +#ifndef _SELINUX_CALLBACKS_H_ +#define _SELINUX_CALLBACKS_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <selinux/selinux.h> +#include "dso.h" + +/* callback pointers */ +extern int __attribute__ ((format(printf, 2, 3))) +(*selinux_log) (int type, const char *, ...) hidden; + +extern int +(*selinux_audit) (void *, security_class_t, char *, size_t) hidden; + +extern int +(*selinux_validate)(char **ctx) hidden; + +extern int +(*selinux_netlink_setenforce) (int enforcing) hidden; + +extern int +(*selinux_netlink_policyload) (int seqno) hidden; + +#endif /* _SELINUX_CALLBACKS_H_ */
diff --git a/selinux/libselinux/src/canonicalize_context.c b/selinux/libselinux/src/canonicalize_context.c new file mode 100644 index 0000000..7cf3139 --- /dev/null +++ b/selinux/libselinux/src/canonicalize_context.c
@@ -0,0 +1,86 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <limits.h> + +int security_canonicalize_context_raw(const char * con, + char ** canoncon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/context", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + strncpy(buf, con, size); + + ret = write(fd, buf, strlen(buf) + 1); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0 && errno == EINVAL) { + /* Fall back to the original context for kernels + that do not support the extended interface. */ + strncpy(buf, con, size); + } + + *canoncon = strdup(buf); + if (!(*canoncon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_canonicalize_context_raw) + +int security_canonicalize_context(const char * con, + char ** canoncon) +{ + int ret; + char * rcon; + char * rcanoncon; + + if (selinux_trans_to_raw_context(con, &rcon)) + return -1; + + ret = security_canonicalize_context_raw(rcon, &rcanoncon); + + freecon(rcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rcanoncon, canoncon); + freecon(rcanoncon); + } + + return ret; +} + +hidden_def(security_canonicalize_context)
diff --git a/selinux/libselinux/src/checkAccess.c b/selinux/libselinux/src/checkAccess.c new file mode 100644 index 0000000..8de5747 --- /dev/null +++ b/selinux/libselinux/src/checkAccess.c
@@ -0,0 +1,118 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#include <unistd.h> +#include <sys/types.h> +#include <stdlib.h> +#include <errno.h> +#include "selinux_internal.h" +#include <selinux/avc.h> +#include "avc_internal.h" + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static int selinux_enabled; + +static int avc_reset_callback(uint32_t event __attribute__((unused)), + security_id_t ssid __attribute__((unused)), + security_id_t tsid __attribute__((unused)), + security_class_t tclass __attribute__((unused)), + access_vector_t perms __attribute__((unused)), + access_vector_t *out_retained __attribute__((unused))) +{ + flush_class_cache(); + return 0; +} + +static void avc_init_once(void) +{ + selinux_enabled = is_selinux_enabled(); + if (selinux_enabled == 1) { + if (avc_open(NULL, 0)) + return; + avc_add_callback(avc_reset_callback, AVC_CALLBACK_RESET, + 0, 0, 0, 0); + } +} + +int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) { + int rc; + security_id_t scon_id; + security_id_t tcon_id; + security_class_t sclass; + access_vector_t av; + + __selinux_once(once, avc_init_once); + + if (selinux_enabled != 1) + return 0; + + rc = avc_context_to_sid(scon, &scon_id); + if (rc < 0) + return rc; + + rc = avc_context_to_sid(tcon, &tcon_id); + if (rc < 0) + return rc; + + (void) avc_netlink_check_nb(); + + sclass = string_to_security_class(class); + if (sclass == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown class %s", class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + av = string_to_av_perm(sclass, perm); + if (av == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", perm, class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); +} + +int selinux_check_passwd_access(access_vector_t requested) +{ + int status = -1; + char *user_context; + if (is_selinux_enabled() == 0) + return 0; + if (getprevcon_raw(&user_context) == 0) { + security_class_t passwd_class; + struct av_decision avd; + int retval; + + passwd_class = string_to_security_class("passwd"); + if (passwd_class == 0) + return 0; + + retval = security_compute_av_raw(user_context, + user_context, + passwd_class, + requested, + &avd); + + if ((retval == 0) && ((requested & avd.allowed) == requested)) { + status = 0; + } + freecon(user_context); + } + + if (status != 0 && security_getenforce() == 0) + status = 0; + + return status; +} + +hidden_def(selinux_check_passwd_access) + +int checkPasswdAccess(access_vector_t requested) +{ + return selinux_check_passwd_access(requested); +}
diff --git a/selinux/libselinux/src/check_context.c b/selinux/libselinux/src/check_context.c new file mode 100644 index 0000000..52063fa --- /dev/null +++ b/selinux/libselinux/src/check_context.c
@@ -0,0 +1,51 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include "selinux_internal.h" +#include "policy.h" +#include <limits.h> + +int security_check_context_raw(const char * con) +{ + char path[PATH_MAX]; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/context", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + ret = write(fd, con, strlen(con) + 1); + close(fd); + if (ret < 0) + return -1; + return 0; +} + +hidden_def(security_check_context_raw) + +int security_check_context(const char * con) +{ + int ret; + char * rcon; + + if (selinux_trans_to_raw_context(con, &rcon)) + return -1; + + ret = security_check_context_raw(rcon); + + freecon(rcon); + + return ret; +} + +hidden_def(security_check_context)
diff --git a/selinux/libselinux/src/compute_av.c b/selinux/libselinux/src/compute_av.c new file mode 100644 index 0000000..937e5c3 --- /dev/null +++ b/selinux/libselinux/src/compute_av.c
@@ -0,0 +1,157 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_av_flags_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + char path[PATH_MAX]; + char *buf; + size_t len; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/access", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + len = selinux_page_size; + buf = malloc(len); + if (!buf) { + ret = -1; + goto out; + } + + snprintf(buf, len, "%s %s %hu %x", scon, tcon, + unmap_class(tclass), unmap_perm(tclass, requested)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, len); + ret = read(fd, buf, len - 1); + if (ret < 0) + goto out2; + + ret = sscanf(buf, "%x %x %x %x %u %x", + &avd->allowed, &avd->decided, + &avd->auditallow, &avd->auditdeny, + &avd->seqno, &avd->flags); + if (ret < 5) { + ret = -1; + goto out2; + } else if (ret < 6) + avd->flags = 0; + + /* If tclass invalid, kernel sets avd according to deny_unknown flag */ + if (tclass != 0) + map_decision(tclass, avd); + + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_av_flags_raw) + +int security_compute_av_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags_raw(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + return ret; +} + +hidden_def(security_compute_av_raw) + +int security_compute_av_flags(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + char * rscon; + char * rtcon; + int ret; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + ret = security_compute_av_flags_raw(rscon, rtcon, tclass, + requested, avd); + + freecon(rscon); + freecon(rtcon); + + return ret; +} + +hidden_def(security_compute_av_flags) + +int security_compute_av(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) + { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + + return ret; +} + +hidden_def(security_compute_av)
diff --git a/selinux/libselinux/src/compute_create.c b/selinux/libselinux/src/compute_create.c new file mode 100644 index 0000000..9559d42 --- /dev/null +++ b/selinux/libselinux/src/compute_create.c
@@ -0,0 +1,158 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +static int object_name_encode(const char *objname, char *buffer, size_t buflen) +{ + int code; + size_t offset = 0; + + if (buflen - offset < 1) + return -1; + buffer[offset++] = ' '; + + do { + code = *objname++; + + if (isalnum(code) || code == '\0' || code == '-' || + code == '.' || code == '_' || code == '~') { + if (buflen - offset < 1) + return -1; + buffer[offset++] = code; + } else if (code == ' ') { + if (buflen - offset < 1) + return -1; + buffer[offset++] = '+'; + } else { + static const char *table = "0123456789ABCDEF"; + int l = (code & 0x0f); + int h = (code & 0xf0) >> 4; + + if (buflen - offset < 3) + return -1; + buffer[offset++] = '%'; + buffer[offset++] = table[h]; + buffer[offset++] = table[l]; + } + } while (code != '\0'); + + return 0; +} + +int security_compute_create_name_raw(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret, len; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/create", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + len = snprintf(buf, size, "%s %s %hu", + scon, tcon, unmap_class(tclass)); + if (objname && + object_name_encode(objname, buf + len, size - len) < 0) { + errno = ENAMETOOLONG; + ret = -1; + goto out2; + } + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!(*newcon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} +hidden_def(security_compute_create_name_raw) + +int security_compute_create_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + return security_compute_create_name_raw(scon, tcon, tclass, + NULL, newcon); +} +hidden_def(security_compute_create_raw) + +int security_compute_create_name(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_create_name_raw(rscon, rtcon, tclass, + objname, &rnewcon); + freecon(rscon); + freecon(rtcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rnewcon, newcon); + freecon(rnewcon); + } + + return ret; +} +hidden_def(security_compute_create_name) + +int security_compute_create(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + return security_compute_create_name(scon, tcon, tclass, NULL, newcon); +} +hidden_def(security_compute_create)
diff --git a/selinux/libselinux/src/compute_member.c b/selinux/libselinux/src/compute_member.c new file mode 100644 index 0000000..1fc7e41 --- /dev/null +++ b/selinux/libselinux/src/compute_member.c
@@ -0,0 +1,95 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_member_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/member", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!(*newcon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_member_raw) + +int security_compute_member(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_member_raw(rscon, rtcon, tclass, &rnewcon); + + freecon(rscon); + freecon(rtcon); + if (!ret) { + if (selinux_raw_to_trans_context(rnewcon, newcon)) { + *newcon = NULL; + ret = -1; + } + freecon(rnewcon); + } + + return ret; +}
diff --git a/selinux/libselinux/src/compute_relabel.c b/selinux/libselinux/src/compute_relabel.c new file mode 100644 index 0000000..4615aee --- /dev/null +++ b/selinux/libselinux/src/compute_relabel.c
@@ -0,0 +1,92 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_relabel_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/relabel", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!*newcon) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_relabel_raw) + +int security_compute_relabel(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_relabel_raw(rscon, rtcon, tclass, &rnewcon); + + freecon(rscon); + freecon(rtcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rnewcon, newcon); + freecon(rnewcon); + } + + return ret; +}
diff --git a/selinux/libselinux/src/compute_user.c b/selinux/libselinux/src/compute_user.c new file mode 100644 index 0000000..b37c5d3 --- /dev/null +++ b/selinux/libselinux/src/compute_user.c
@@ -0,0 +1,110 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <limits.h> + +int security_compute_user_raw(const char * scon, + const char *user, char *** con) +{ + char path[PATH_MAX]; + char **ary; + char *buf, *ptr; + size_t size; + int fd, ret; + unsigned int i, nel; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/user", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s", scon, user); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + if (sscanf(buf, "%u", &nel) != 1) { + ret = -1; + goto out2; + } + + ary = malloc((nel + 1) * sizeof(char *)); + if (!ary) { + ret = -1; + goto out2; + } + + ptr = buf + strlen(buf) + 1; + for (i = 0; i < nel; i++) { + ary[i] = strdup(ptr); + if (!ary[i]) { + freeconary(ary); + ret = -1; + goto out2; + } + ptr += strlen(ptr) + 1; + } + ary[nel] = NULL; + *con = ary; + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_user_raw) + +int security_compute_user(const char * scon, + const char *user, char *** con) +{ + int ret; + char * rscon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + + ret = security_compute_user_raw(rscon, user, con); + + freecon(rscon); + if (!ret) { + char **ptr, *tmpcon; + for (ptr = *con; *ptr; ptr++) { + if (selinux_raw_to_trans_context(*ptr, &tmpcon)) { + freeconary(*con); + *con = NULL; + return -1; + } + freecon(*ptr); + *ptr = tmpcon; + } + } + + return ret; +} + +hidden_def(security_compute_user)
diff --git a/selinux/libselinux/src/context.c b/selinux/libselinux/src/context.c new file mode 100644 index 0000000..b673733 --- /dev/null +++ b/selinux/libselinux/src/context.c
@@ -0,0 +1,195 @@ +#include "context_internal.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#define COMP_USER 0 +#define COMP_ROLE 1 +#define COMP_TYPE 2 +#define COMP_RANGE 3 + +typedef struct { + char *current_str; /* This is made up-to-date only when needed */ + char *(component[4]); +} context_private_t; + +/* + * Allocate a new context, initialized from str. There must be 3 or + * 4 colon-separated components and no whitespace in any component other + * than the MLS component. + */ +context_t context_new(const char *str) +{ + int i, count; + errno = 0; + context_private_t *n = + (context_private_t *) malloc(sizeof(context_private_t)); + context_t result = (context_t) malloc(sizeof(context_s_t)); + const char *p, *tok; + + if (result) + result->ptr = n; + else + free(n); + if (n == 0 || result == 0) { + goto err; + } + n->current_str = n->component[0] = n->component[1] = n->component[2] = + n->component[3] = 0; + for (i = count = 0, p = str; *p; p++) { + switch (*p) { + case ':': + count++; + break; + case '\n': + case '\t': + case '\r': + goto err; /* sanity check */ + case ' ': + if (count < 3) + goto err; /* sanity check */ + } + } + /* + * Could be anywhere from 2 - 5 + * e.g user:role:type to user:role:type:sens1:cata-sens2:catb + */ + if (count < 2 || count > 5) { /* might not have a range */ + goto err; + } + + n->component[3] = 0; + for (i = 0, tok = str; *tok; i++) { + if (i < 3) + for (p = tok; *p && *p != ':'; p++) { /* empty */ + } else { + /* MLS range is one component */ + for (p = tok; *p; p++) { /* empty */ + } + } + n->component[i] = (char *)malloc(p - tok + 1); + if (n->component[i] == 0) + goto err; + strncpy(n->component[i], tok, p - tok); + n->component[i][p - tok] = '\0'; + tok = *p ? p + 1 : p; + } + return result; + err: + if (errno == 0) errno = EINVAL; + context_free(result); + return 0; +} + +hidden_def(context_new) + +static void conditional_free(char **v) +{ + if (*v) { + free(*v); + } + *v = 0; +} + +/* + * free all storage used by a context. Safe to call with + * null pointer. + */ +void context_free(context_t context) +{ + context_private_t *n; + int i; + if (context) { + n = context->ptr; + if (n) { + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + conditional_free(&n->component[i]); + } + free(n); + } + free(context); + } +} + +hidden_def(context_free) + +/* + * Return a pointer to the string value of the context. + */ +char *context_str(context_t context) +{ + context_private_t *n = context->ptr; + int i; + size_t total = 0; + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + if (n->component[i]) { + total += strlen(n->component[i]) + 1; + } + } + n->current_str = malloc(total); + if (n->current_str != 0) { + char *cp = n->current_str; + + cp = stpcpy(cp, n->component[0]); + for (i = 1; i < 4; i++) { + if (n->component[i]) { + *cp++ = ':'; + cp = stpcpy(cp, n->component[i]); + } + } + } + return n->current_str; +} + +hidden_def(context_str) + +/* Returns nonzero iff failed */ +static int set_comp(context_private_t * n, int idx, const char *str) +{ + char *t = NULL; + const char *p; + if (str) { + t = (char *)malloc(strlen(str) + 1); + if (!t) { + return 1; + } + for (p = str; *p; p++) { + if (*p == '\t' || *p == '\n' || *p == '\r' || + ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { + free(t); + errno = EINVAL; + return 1; + } + } + strcpy(t, str); + } + conditional_free(&n->component[idx]); + n->component[idx] = t; + return 0; +} + +#define def_get(name,tag) \ +const char * context_ ## name ## _get(context_t context) \ +{ \ + context_private_t *n = context->ptr; \ + return n->component[tag]; \ +} \ +hidden_def(context_ ## name ## _get) + +def_get(type, COMP_TYPE) + def_get(user, COMP_USER) + def_get(range, COMP_RANGE) + def_get(role, COMP_ROLE) +#define def_set(name,tag) \ +int context_ ## name ## _set(context_t context, const char* str) \ +{ \ + return set_comp(context->ptr,tag,str);\ +} \ +hidden_def(context_ ## name ## _set) + def_set(type, COMP_TYPE) + def_set(role, COMP_ROLE) + def_set(user, COMP_USER) + def_set(range, COMP_RANGE)
diff --git a/selinux/libselinux/src/context_internal.h b/selinux/libselinux/src/context_internal.h new file mode 100644 index 0000000..3c71e80 --- /dev/null +++ b/selinux/libselinux/src/context_internal.h
@@ -0,0 +1,14 @@ +#include <selinux/context.h> +#include "dso.h" + +hidden_proto(context_new) + hidden_proto(context_free) + hidden_proto(context_str) + hidden_proto(context_type_set) + hidden_proto(context_type_get) + hidden_proto(context_role_set) + hidden_proto(context_role_get) + hidden_proto(context_user_set) + hidden_proto(context_user_get) + hidden_proto(context_range_set) + hidden_proto(context_range_get)
diff --git a/selinux/libselinux/src/deny_unknown.c b/selinux/libselinux/src/deny_unknown.c new file mode 100644 index 0000000..c93998a --- /dev/null +++ b/selinux/libselinux/src/deny_unknown.c
@@ -0,0 +1,40 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <stdio.h> +#include <limits.h> + +int security_deny_unknown(void) +{ + int fd, ret, deny_unknown = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof(path), "%s/deny_unknown", selinux_mnt); + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &deny_unknown) != 1) + return -1; + + return deny_unknown; +} + +hidden_def(security_deny_unknown);
diff --git a/selinux/libselinux/src/disable.c b/selinux/libselinux/src/disable.c new file mode 100644 index 0000000..dac0f5b --- /dev/null +++ b/selinux/libselinux/src/disable.c
@@ -0,0 +1,38 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <stdio.h> +#include <limits.h> + +int security_disable(void) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/disable", selinux_mnt); + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + buf[0] = '1'; + buf[1] = '\0'; + ret = write(fd, buf, strlen(buf)); + close(fd); + if (ret < 0) + return -1; + + return 0; +} + +hidden_def(security_disable)
diff --git a/selinux/libselinux/src/dso.h b/selinux/libselinux/src/dso.h new file mode 100644 index 0000000..12c3d11 --- /dev/null +++ b/selinux/libselinux/src/dso.h
@@ -0,0 +1,23 @@ +#ifndef _SELINUX_DSO_H +#define _SELINUX_DSO_H 1 + +#ifdef SHARED +# define hidden __attribute__ ((visibility ("hidden"))) +# define hidden_proto(fct) __hidden_proto (fct, fct##_internal) +# define __hidden_proto(fct, internal) \ + extern __typeof (fct) internal; \ + extern __typeof (fct) fct __asm (#internal) hidden; +# if defined(__alpha__) || defined(__mips__) +# define hidden_def(fct) \ + asm (".globl " #fct "\n" #fct " = " #fct "_internal"); +# else +# define hidden_def(fct) \ + asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); +#endif +#else +# define hidden +# define hidden_proto(fct) +# define hidden_def(fct) +#endif + +#endif
diff --git a/selinux/libselinux/src/enabled.c b/selinux/libselinux/src/enabled.c new file mode 100644 index 0000000..2ec6797 --- /dev/null +++ b/selinux/libselinux/src/enabled.c
@@ -0,0 +1,58 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include "selinux_internal.h" +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include "policy.h" + +int is_selinux_enabled(void) +{ + /* init_selinuxmnt() gets called before this function. We + * will assume that if a selinux file system is mounted, then + * selinux is enabled. */ +#ifdef ANDROID + return (selinux_mnt ? 1 : 0); +#else + return (selinux_mnt && has_selinux_config); +#endif +} + +hidden_def(is_selinux_enabled) + +/* + * Function: is_selinux_mls_enabled() + * Return: 1 on success + * 0 on failure + */ +int is_selinux_mls_enabled(void) +{ + char buf[20], path[PATH_MAX]; + int fd, ret, enabled = 0; + + if (!selinux_mnt) + return enabled; + + snprintf(path, sizeof path, "%s/mls", selinux_mnt); + fd = open(path, O_RDONLY); + if (fd < 0) + return enabled; + + memset(buf, 0, sizeof buf); + + do { + ret = read(fd, buf, sizeof buf - 1); + } while (ret < 0 && errno == EINTR); + close(fd); + if (ret < 0) + return enabled; + + if (!strcmp(buf, "1")) + enabled = 1; + + return enabled; +} + +hidden_def(is_selinux_mls_enabled)
diff --git a/selinux/libselinux/src/exception.sh b/selinux/libselinux/src/exception.sh new file mode 100755 index 0000000..a58bf3f --- /dev/null +++ b/selinux/libselinux/src/exception.sh
@@ -0,0 +1,20 @@ +function except() { +case $1 in + selinux_file_context_cmp) # ignore + ;; + *) +echo " +%exception $1 { + \$action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } +} +" +;; +esac +} +${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h +for i in `awk '/<stdin>.*extern int/ { print $6 }' temp.aux`; do except $i ; done +rm -f -- temp.aux -.o
diff --git a/selinux/libselinux/src/fgetfilecon.c b/selinux/libselinux/src/fgetfilecon.c new file mode 100644 index 0000000..3954e64 --- /dev/null +++ b/selinux/libselinux/src/fgetfilecon.c
@@ -0,0 +1,72 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "selinux_internal.h" +#include "policy.h" + +int fgetfilecon_raw(int fd, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(fgetfilecon_raw) + +int fgetfilecon(int fd, char ** context) +{ + char * rcontext; + int ret; + + *context = NULL; + + ret = fgetfilecon_raw(fd, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + if (ret >= 0 && *context) + return strlen(*context) + 1; + + return ret; +}
diff --git a/selinux/libselinux/src/file_path_suffixes.h b/selinux/libselinux/src/file_path_suffixes.h new file mode 100644 index 0000000..d1f9b48 --- /dev/null +++ b/selinux/libselinux/src/file_path_suffixes.h
@@ -0,0 +1,31 @@ +/* File name suffixes. */ +S_(BINPOLICY, "/policy/policy") + S_(CONTEXTS_DIR, "/contexts") + S_(FILE_CONTEXTS, "/contexts/files/file_contexts") + S_(HOMEDIR_CONTEXTS, "/contexts/files/homedir_template") + S_(DEFAULT_CONTEXTS, "/contexts/default_contexts") + S_(USER_CONTEXTS, "/contexts/users/") + S_(FAILSAFE_CONTEXT, "/contexts/failsafe_context") + S_(DEFAULT_TYPE, "/contexts/default_type") + S_(SECURETTY_TYPES, "/contexts/securetty_types") + S_(BOOLEANS, "/booleans") + S_(MEDIA_CONTEXTS, "/contexts/files/media") + S_(REMOVABLE_CONTEXT, "/contexts/removable_context") + S_(CUSTOMIZABLE_TYPES, "/contexts/customizable_types") + S_(USERS_DIR, "/users/") + S_(SEUSERS, "/seusers") + S_(TRANSLATIONS, "/setrans.conf") + S_(NETFILTER_CONTEXTS, "/contexts/netfilter_contexts") + S_(FILE_CONTEXTS_HOMEDIR, "/contexts/files/file_contexts.homedirs") + S_(FILE_CONTEXTS_LOCAL, "/contexts/files/file_contexts.local") + S_(X_CONTEXTS, "/contexts/x_contexts") + S_(COLORS, "/secolor.conf") + S_(VIRTUAL_DOMAIN, "/contexts/virtual_domain_context") + S_(VIRTUAL_IMAGE, "/contexts/virtual_image_context") + S_(LXC_CONTEXTS, "/contexts/lxc_contexts") + S_(OPENSSH_CONTEXTS, "/contexts/openssh_contexts") + S_(SYSTEMD_CONTEXTS, "/contexts/systemd_contexts") + S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs") + S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist") + S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts") + S_(BOOLEAN_SUBS, "/booleans.subs_dist")
diff --git a/selinux/libselinux/src/freecon.c b/selinux/libselinux/src/freecon.c new file mode 100644 index 0000000..5290dfa --- /dev/null +++ b/selinux/libselinux/src/freecon.c
@@ -0,0 +1,11 @@ +#include <unistd.h> +#include "selinux_internal.h" +#include <stdlib.h> +#include <errno.h> + +void freecon(char * con) +{ + free(con); +} + +hidden_def(freecon)
diff --git a/selinux/libselinux/src/freeconary.c b/selinux/libselinux/src/freeconary.c new file mode 100644 index 0000000..8d07718 --- /dev/null +++ b/selinux/libselinux/src/freeconary.c
@@ -0,0 +1,19 @@ +#include <unistd.h> +#include "selinux_internal.h" +#include <stdlib.h> +#include <errno.h> + +void freeconary(char ** con) +{ + char **ptr; + + if (!con) + return; + + for (ptr = con; *ptr; ptr++) { + free(*ptr); + } + free(con); +} + +hidden_def(freeconary)
diff --git a/selinux/libselinux/src/fsetfilecon.c b/selinux/libselinux/src/fsetfilecon.c new file mode 100644 index 0000000..52707d0 --- /dev/null +++ b/selinux/libselinux/src/fsetfilecon.c
@@ -0,0 +1,43 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "selinux_internal.h" +#include "policy.h" + +int fsetfilecon_raw(int fd, const char * context) +{ + int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, + 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((fgetfilecon_raw(fd, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(fsetfilecon_raw) + +int fsetfilecon(int fd, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = fsetfilecon_raw(fd, rcontext); + + freecon(rcontext); + + return ret; +}
diff --git a/selinux/libselinux/src/get_context_list.c b/selinux/libselinux/src/get_context_list.c new file mode 100644 index 0000000..f3fa4a9 --- /dev/null +++ b/selinux/libselinux/src/get_context_list.c
@@ -0,0 +1,526 @@ +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <pwd.h> +#include "selinux_internal.h" +#include "context_internal.h" +#include "get_context_list_internal.h" + +int get_default_context_with_role(const char *user, + const char *role, + char * fromcon, + char ** newcon) +{ + char **conary; + char **ptr; + context_t con; + const char *role2; + int rc; + + rc = get_ordered_context_list(user, fromcon, &conary); + if (rc <= 0) + return -1; + + for (ptr = conary; *ptr; ptr++) { + con = context_new(*ptr); + if (!con) + continue; + role2 = context_role_get(con); + if (role2 && !strcmp(role, role2)) { + context_free(con); + break; + } + context_free(con); + } + + rc = -1; + if (!(*ptr)) { + errno = EINVAL; + goto out; + } + *newcon = strdup(*ptr); + if (!(*newcon)) + goto out; + rc = 0; + out: + freeconary(conary); + return rc; +} + +hidden_def(get_default_context_with_role) + +int get_default_context_with_rolelevel(const char *user, + const char *role, + const char *level, + char * fromcon, + char ** newcon) +{ + + int rc = 0; + int freefrom = 0; + context_t con; + char *newfromcon; + if (!level) + return get_default_context_with_role(user, role, fromcon, + newcon); + + if (!fromcon) { + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + rc = -1; + con = context_new(fromcon); + if (!con) + goto out; + + if (context_range_set(con, level)) + goto out; + + newfromcon = context_str(con); + if (!newfromcon) + goto out; + + rc = get_default_context_with_role(user, role, newfromcon, newcon); + + out: + context_free(con); + if (freefrom) + freecon(fromcon); + return rc; + +} + +int get_default_context(const char *user, + char * fromcon, char ** newcon) +{ + char **conary; + int rc; + + rc = get_ordered_context_list(user, fromcon, &conary); + if (rc <= 0) + return -1; + + *newcon = strdup(conary[0]); + freeconary(conary); + if (!(*newcon)) + return -1; + return 0; +} + +static int find_partialcon(char ** list, + unsigned int nreach, char *part) +{ + const char *conrole, *contype; + char *partrole, *parttype, *ptr; + context_t con; + unsigned int i; + + partrole = part; + ptr = part; + while (*ptr && !isspace(*ptr) && *ptr != ':') + ptr++; + if (*ptr != ':') + return -1; + *ptr++ = 0; + parttype = ptr; + while (*ptr && !isspace(*ptr) && *ptr != ':') + ptr++; + *ptr = 0; + + for (i = 0; i < nreach; i++) { + con = context_new(list[i]); + if (!con) + return -1; + conrole = context_role_get(con); + contype = context_type_get(con); + if (!conrole || !contype) { + context_free(con); + return -1; + } + if (!strcmp(conrole, partrole) && !strcmp(contype, parttype)) { + context_free(con); + return i; + } + context_free(con); + } + + return -1; +} + +static int get_context_order(FILE * fp, + char * fromcon, + char ** reachable, + unsigned int nreach, + unsigned int *ordering, unsigned int *nordered) +{ + char *start, *end = NULL; + char *line = NULL; + size_t line_len = 0; + ssize_t len; + int found = 0; + const char *fromrole, *fromtype; + char *linerole, *linetype; + unsigned int i; + context_t con; + int rc; + + errno = -EINVAL; + + /* Extract the role and type of the fromcon for matching. + User identity and MLS range can be variable. */ + con = context_new(fromcon); + if (!con) + return -1; + fromrole = context_role_get(con); + fromtype = context_type_get(con); + if (!fromrole || !fromtype) { + context_free(con); + return -1; + } + + while ((len = getline(&line, &line_len, fp)) > 0) { + if (line[len - 1] == '\n') + line[len - 1] = 0; + + /* Skip leading whitespace. */ + start = line; + while (*start && isspace(*start)) + start++; + if (!(*start)) + continue; + + /* Find the end of the (partial) fromcon in the line. */ + end = start; + while (*end && !isspace(*end)) + end++; + if (!(*end)) + continue; + + /* Check for a match. */ + linerole = start; + while (*start && !isspace(*start) && *start != ':') + start++; + if (*start != ':') + continue; + *start = 0; + linetype = ++start; + while (*start && !isspace(*start) && *start != ':') + start++; + if (!(*start)) + continue; + *start = 0; + if (!strcmp(fromrole, linerole) && !strcmp(fromtype, linetype)) { + found = 1; + break; + } + } + + if (!found) { + errno = ENOENT; + rc = -1; + goto out; + } + + start = ++end; + while (*start) { + /* Skip leading whitespace */ + while (*start && isspace(*start)) + start++; + if (!(*start)) + break; + + /* Find the end of this partial context. */ + end = start; + while (*end && !isspace(*end)) + end++; + if (*end) + *end++ = 0; + + /* Check for a match in the reachable list. */ + rc = find_partialcon(reachable, nreach, start); + if (rc < 0) { + /* No match, skip it. */ + start = end; + continue; + } + + /* If a match is found and the entry is not already ordered + (e.g. due to prior match in prior config file), then set + the ordering for it. */ + i = rc; + if (ordering[i] == nreach) + ordering[i] = (*nordered)++; + start = end; + } + + rc = 0; + + out: + context_free(con); + free(line); + return rc; +} + +static int get_failsafe_context(const char *user, char ** newcon) +{ + FILE *fp; + char buf[255], *ptr; + size_t plen, nlen; + int rc; + + fp = fopen(selinux_failsafe_context_path(), "r"); + if (!fp) + return -1; + + ptr = fgets_unlocked(buf, sizeof buf, fp); + fclose(fp); + + if (!ptr) + return -1; + plen = strlen(ptr); + if (buf[plen - 1] == '\n') + buf[plen - 1] = 0; + + nlen = strlen(user) + 1 + plen + 1; + *newcon = malloc(nlen); + if (!(*newcon)) + return -1; + rc = snprintf(*newcon, nlen, "%s:%s", user, ptr); + if (rc < 0 || (size_t) rc >= nlen) { + free(*newcon); + *newcon = 0; + return -1; + } + + /* If possible, check the context to catch + errors early rather than waiting until the + caller tries to use setexeccon on the context. + But this may not always be possible, e.g. if + selinuxfs isn't mounted. */ + if (security_check_context(*newcon) && errno != ENOENT) { + free(*newcon); + *newcon = 0; + return -1; + } + + return 0; +} + +struct context_order { + char * con; + unsigned int order; +}; + +static int order_compare(const void *A, const void *B) +{ + const struct context_order *c1 = A, *c2 = B; + if (c1->order < c2->order) + return -1; + else if (c1->order > c2->order) + return 1; + return strcmp(c1->con, c2->con); +} + +int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, + char *** list) +{ + int rc; + int freefrom = 0; + context_t con; + char *newfromcon; + + if (!level) + return get_ordered_context_list(user, fromcon, list); + + if (!fromcon) { + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + rc = -1; + con = context_new(fromcon); + if (!con) + goto out; + + if (context_range_set(con, level)) + goto out; + + newfromcon = context_str(con); + if (!newfromcon) + goto out; + + rc = get_ordered_context_list(user, newfromcon, list); + + out: + context_free(con); + if (freefrom) + freecon(fromcon); + return rc; +} + +hidden_def(get_ordered_context_list_with_level) + +int get_default_context_with_level(const char *user, + const char *level, + char * fromcon, + char ** newcon) +{ + char **conary; + int rc; + + rc = get_ordered_context_list_with_level(user, level, fromcon, &conary); + if (rc <= 0) + return -1; + + *newcon = strdup(conary[0]); + freeconary(conary); + if (!(*newcon)) + return -1; + return 0; +} + +int get_ordered_context_list(const char *user, + char * fromcon, + char *** list) +{ + char **reachable = NULL; + unsigned int *ordering = NULL; + struct context_order *co = NULL; + char **ptr; + int rc = 0; + unsigned int nreach = 0, nordered = 0, freefrom = 0, i; + FILE *fp; + char *fname = NULL; + size_t fname_len; + const char *user_contexts_path = selinux_user_contexts_path(); + + if (!fromcon) { + /* Get the current context and use it for the starting context */ + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + /* Determine the set of reachable contexts for the user. */ + rc = security_compute_user(fromcon, user, &reachable); + if (rc < 0) + goto failsafe; + nreach = 0; + for (ptr = reachable; *ptr; ptr++) + nreach++; + if (!nreach) + goto failsafe; + + /* Initialize ordering array. */ + ordering = malloc(nreach * sizeof(unsigned int)); + if (!ordering) + goto failsafe; + for (i = 0; i < nreach; i++) + ordering[i] = nreach; + + /* Determine the ordering to apply from the optional per-user config + and from the global config. */ + fname_len = strlen(user_contexts_path) + strlen(user) + 2; + fname = malloc(fname_len); + if (!fname) + goto failsafe; + snprintf(fname, fname_len, "%s%s", user_contexts_path, user); + fp = fopen(fname, "r"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + rc = get_context_order(fp, fromcon, reachable, nreach, ordering, + &nordered); + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, + "%s: error in processing configuration file %s\n", + __FUNCTION__, fname); + /* Fall through, try global config */ + } + } + free(fname); + fp = fopen(selinux_default_context_path(), "r"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + rc = get_context_order(fp, fromcon, reachable, nreach, ordering, + &nordered); + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, + "%s: error in processing configuration file %s\n", + __FUNCTION__, selinux_default_context_path()); + /* Fall through */ + } + rc = 0; + } + + if (!nordered) + goto failsafe; + + /* Apply the ordering. */ + co = malloc(nreach * sizeof(struct context_order)); + if (!co) + goto failsafe; + for (i = 0; i < nreach; i++) { + co[i].con = reachable[i]; + co[i].order = ordering[i]; + } + qsort(co, nreach, sizeof(struct context_order), order_compare); + for (i = 0; i < nreach; i++) + reachable[i] = co[i].con; + free(co); + + /* Only report the ordered entries to the caller. */ + if (nordered <= nreach) { + for (i = nordered; i < nreach; i++) + free(reachable[i]); + reachable[nordered] = NULL; + rc = nordered; + } + + out: + if (rc > 0) + *list = reachable; + else + freeconary(reachable); + + free(ordering); + if (freefrom) + freecon(fromcon); + + return rc; + + failsafe: + /* Unable to determine a reachable context list, try to fall back to + the "failsafe" context to at least permit root login + for emergency recovery if possible. */ + freeconary(reachable); + reachable = malloc(2 * sizeof(char *)); + if (!reachable) { + rc = -1; + goto out; + } + reachable[0] = reachable[1] = 0; + rc = get_failsafe_context(user, &reachable[0]); + if (rc < 0) { + freeconary(reachable); + reachable = NULL; + goto out; + } + rc = 1; /* one context in the list */ + goto out; +} + +hidden_def(get_ordered_context_list)
diff --git a/selinux/libselinux/src/get_context_list_internal.h b/selinux/libselinux/src/get_context_list_internal.h new file mode 100644 index 0000000..c224834 --- /dev/null +++ b/selinux/libselinux/src/get_context_list_internal.h
@@ -0,0 +1,6 @@ +#include <selinux/get_context_list.h> +#include "dso.h" + +hidden_proto(get_ordered_context_list) + hidden_proto(get_ordered_context_list_with_level) + hidden_proto(get_default_context_with_role)
diff --git a/selinux/libselinux/src/get_default_type.c b/selinux/libselinux/src/get_default_type.c new file mode 100644 index 0000000..27f2ae5 --- /dev/null +++ b/selinux/libselinux/src/get_default_type.c
@@ -0,0 +1,71 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "get_default_type_internal.h" +#include <errno.h> + +static int find_default_type(FILE * fp, const char *role, char **type); + +int get_default_type(const char *role, char **type) +{ + FILE *fp = NULL; + + fp = fopen(selinux_default_type_path(), "r"); + if (!fp) + return -1; + + if (find_default_type(fp, role, type) < 0) { + fclose(fp); + return -1; + } + + fclose(fp); + return 0; +} + +static int find_default_type(FILE * fp, const char *role, char **type) +{ + char buf[250]; + const char *ptr = "", *end; + char *t; + size_t len; + int found = 0; + + len = strlen(role); + while (!feof_unlocked(fp)) { + if (!fgets_unlocked(buf, sizeof buf, fp)) { + errno = EINVAL; + return -1; + } + if (buf[strlen(buf) - 1]) + buf[strlen(buf) - 1] = 0; + + ptr = buf; + while (*ptr && isspace(*ptr)) + ptr++; + if (!(*ptr)) + continue; + + if (!strncmp(role, ptr, len)) { + end = ptr + len; + if (*end == ':') { + found = 1; + ptr = ++end; + break; + } + } + } + + if (!found) { + errno = EINVAL; + return -1; + } + + t = malloc(strlen(buf) - len); + if (!t) + return -1; + strcpy(t, ptr); + *type = t; + return 0; +}
diff --git a/selinux/libselinux/src/get_default_type_internal.h b/selinux/libselinux/src/get_default_type_internal.h new file mode 100644 index 0000000..0da3c51 --- /dev/null +++ b/selinux/libselinux/src/get_default_type_internal.h
@@ -0,0 +1,4 @@ +#include <selinux/get_default_type.h> +#include "dso.h" + +hidden_proto(selinux_default_type_path)
diff --git a/selinux/libselinux/src/get_initial_context.c b/selinux/libselinux/src/get_initial_context.c new file mode 100644 index 0000000..522ed78 --- /dev/null +++ b/selinux/libselinux/src/get_initial_context.c
@@ -0,0 +1,72 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <limits.h> + +#define SELINUX_INITCON_DIR "/initial_contexts/" + +int security_get_initial_context_raw(const char * name, char ** con) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s%s%s", + selinux_mnt, SELINUX_INITCON_DIR, name); + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *con = strdup(buf); + if (!(*con)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_get_initial_context_raw) + +int security_get_initial_context(const char * name, char ** con) +{ + int ret; + char * rcon; + + ret = security_get_initial_context_raw(name, &rcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rcon, con); + freecon(rcon); + } + + return ret; +} + +hidden_def(security_get_initial_context)
diff --git a/selinux/libselinux/src/getenforce.c b/selinux/libselinux/src/getenforce.c new file mode 100644 index 0000000..4fb516a --- /dev/null +++ b/selinux/libselinux/src/getenforce.c
@@ -0,0 +1,40 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <stdio.h> +#include <limits.h> + +int security_getenforce(void) +{ + int fd, ret, enforce = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/enforce", selinux_mnt); + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof buf); + ret = read(fd, buf, sizeof buf - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &enforce) != 1) + return -1; + + return enforce; +} + +hidden_def(security_getenforce)
diff --git a/selinux/libselinux/src/getfilecon.c b/selinux/libselinux/src/getfilecon.c new file mode 100644 index 0000000..5d4d483 --- /dev/null +++ b/selinux/libselinux/src/getfilecon.c
@@ -0,0 +1,73 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include "selinux_internal.h" +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "policy.h" + +int getfilecon_raw(const char *path, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = getxattr(path, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(getfilecon_raw) + +int getfilecon(const char *path, char ** context) +{ + int ret; + char * rcontext; + + *context = NULL; + + ret = getfilecon_raw(path, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + if (ret >= 0 && *context) + return strlen(*context) + 1; + + return ret; +} + +hidden_def(getfilecon)
diff --git a/selinux/libselinux/src/getpeercon.c b/selinux/libselinux/src/getpeercon.c new file mode 100644 index 0000000..3a77a2d --- /dev/null +++ b/selinux/libselinux/src/getpeercon.c
@@ -0,0 +1,61 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/socket.h> +#include "selinux_internal.h" +#include "policy.h" + +#ifndef SO_PEERSEC +#define SO_PEERSEC 31 +#endif + +int getpeercon_raw(int fd, char ** context) +{ + char *buf; + socklen_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); + } + out: + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(getpeercon_raw) + +int getpeercon(int fd, char ** context) +{ + int ret; + char * rcontext; + + ret = getpeercon_raw(fd, &rcontext); + + if (!ret) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + return ret; +}
diff --git a/selinux/libselinux/src/init.c b/selinux/libselinux/src/init.c new file mode 100644 index 0000000..3c687a2 --- /dev/null +++ b/selinux/libselinux/src/init.c
@@ -0,0 +1,165 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <dlfcn.h> +#include <sys/statvfs.h> +#include <sys/vfs.h> +#include <stdint.h> +#include <limits.h> + +#include "dso.h" +#include "policy.h" +#include "selinux_internal.h" +#include "setrans_internal.h" + +char *selinux_mnt = NULL; +int selinux_page_size = 0; +int obj_class_compat = 1; + +int has_selinux_config = 0; + +/* Verify the mount point for selinux file system has a selinuxfs. + If the file system: + * Exist, + * Is mounted with an selinux file system, + * The file system is read/write + * then set this as the default file system. +*/ +static int verify_selinuxmnt(const char *mnt) +{ + struct statfs sfbuf; + int rc; + + do { + rc = statfs(mnt, &sfbuf); + } while (rc < 0 && errno == EINTR); + if (rc == 0) { + if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) { + struct statvfs vfsbuf; + rc = statvfs(mnt, &vfsbuf); + if (rc == 0) { + if (!(vfsbuf.f_flag & ST_RDONLY)) { + set_selinuxmnt(mnt); + } + return 0; + } + } + } + + return -1; +} + +int selinuxfs_exists(void) +{ + int exists = 0; + FILE *fp = NULL; + char *buf = NULL; + size_t len; + ssize_t num; + + fp = fopen("/proc/filesystems", "r"); + if (!fp) + return 1; /* Fail as if it exists */ + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + num = getline(&buf, &len, fp); + while (num != -1) { + if (strstr(buf, SELINUXFS)) { + exists = 1; + break; + } + num = getline(&buf, &len, fp); + } + + free(buf); + fclose(fp); + return exists; +} +hidden_def(selinuxfs_exists) + +static void init_selinuxmnt(void) +{ + char *buf=NULL, *p; + FILE *fp=NULL; + size_t len; + ssize_t num; + + if (selinux_mnt) + return; + + if (verify_selinuxmnt(SELINUXMNT) == 0) return; + + if (verify_selinuxmnt(OLDSELINUXMNT) == 0) return; + + /* Drop back to detecting it the long way. */ + if (!selinuxfs_exists()) + goto out; + + /* At this point, the usual spot doesn't have an selinuxfs so + * we look around for it */ + fp = fopen("/proc/mounts", "r"); + if (!fp) + goto out; + + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while ((num = getline(&buf, &len, fp)) != -1) { + char *tmp; + p = strchr(buf, ' '); + if (!p) + goto out; + p++; + tmp = strchr(p, ' '); + if (!tmp) + goto out; + if (!strncmp(tmp + 1, SELINUXFS" ", strlen(SELINUXFS)+1)) { + *tmp = '\0'; + break; + } + } + + /* If we found something, dup it */ + if (num > 0) + verify_selinuxmnt(p); + + out: + free(buf); + if (fp) + fclose(fp); + return; +} + +void fini_selinuxmnt(void) +{ + free(selinux_mnt); + selinux_mnt = NULL; +} + +hidden_def(fini_selinuxmnt) + +void set_selinuxmnt(const char *mnt) +{ + selinux_mnt = strdup(mnt); +} + +hidden_def(set_selinuxmnt) + +static void init_lib(void) __attribute__ ((constructor)); +static void init_lib(void) +{ + selinux_page_size = sysconf(_SC_PAGE_SIZE); + init_selinuxmnt(); +#ifndef ANDROID + has_selinux_config = (access(SELINUXCONFIG, F_OK) == 0); +#endif +} + +static void fini_lib(void) __attribute__ ((destructor)); +static void fini_lib(void) +{ + fini_selinuxmnt(); +}
diff --git a/selinux/libselinux/src/is_customizable_type.c b/selinux/libselinux/src/is_customizable_type.c new file mode 100644 index 0000000..0b33edc --- /dev/null +++ b/selinux/libselinux/src/is_customizable_type.c
@@ -0,0 +1,93 @@ +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <pwd.h> +#include <limits.h> +#include "selinux_internal.h" +#include "context_internal.h" + +static int get_customizable_type_list(char *** retlist) +{ + FILE *fp; + char *buf; + unsigned int ctr = 0, i; + char **list = NULL; + + fp = fopen(selinux_customizable_types_path(), "r"); + if (!fp) + return -1; + + buf = malloc(selinux_page_size); + if (!buf) { + fclose(fp); + return -1; + } + while (fgets_unlocked(buf, selinux_page_size, fp) && ctr < UINT_MAX) { + ctr++; + } + rewind(fp); + if (ctr) { + list = + (char **) calloc(sizeof(char *), + ctr + 1); + if (list) { + i = 0; + while (fgets_unlocked(buf, selinux_page_size, fp) + && i < ctr) { + buf[strlen(buf) - 1] = 0; + list[i] = (char *) strdup(buf); + if (!list[i]) { + unsigned int j; + for (j = 0; j < i; j++) + free(list[j]); + free(list); + list = NULL; + break; + } + i++; + } + } + } + fclose(fp); + free(buf); + if (!list) + return -1; + *retlist = list; + return 0; +} + +static char **customizable_list = NULL; + +int is_context_customizable(const char * scontext) +{ + int i; + const char *type; + context_t c; + + if (!customizable_list) { + if (get_customizable_type_list(&customizable_list) != 0) + return -1; + } + + c = context_new(scontext); + if (!c) + return -1; + + type = context_type_get(c); + if (!type) { + context_free(c); + return -1; + } + + for (i = 0; customizable_list[i]; i++) { + if (strcmp(customizable_list[i], type) == 0) { + context_free(c); + return 1; + } + } + context_free(c); + return 0; +}
diff --git a/selinux/libselinux/src/label.c b/selinux/libselinux/src/label.c new file mode 100644 index 0000000..963bfcb --- /dev/null +++ b/selinux/libselinux/src/label.c
@@ -0,0 +1,475 @@ +/* + * Generalized labeling frontend for userspace object managers. + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + */ + +#include <sys/types.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <selinux/selinux.h> +#include "callbacks.h" +#include "label_internal.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +typedef int (*selabel_initfunc)(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts); + +static selabel_initfunc initfuncs[] = { + &selabel_file_init, + &selabel_media_init, + &selabel_x_init, + &selabel_db_init, + &selabel_property_init, +}; + +static void selabel_subs_fini(struct selabel_sub *ptr) +{ + struct selabel_sub *next; + + while (ptr) { + next = ptr->next; + free(ptr->src); + free(ptr->dst); + free(ptr); + ptr = next; + } +} + +static char *selabel_sub(struct selabel_sub *ptr, const char *src) +{ + char *dst = NULL; + int len; + + while (ptr) { + if (strncmp(src, ptr->src, ptr->slen) == 0 ) { + if (src[ptr->slen] == '/' || + src[ptr->slen] == 0) { + if ((src[ptr->slen] == '/') && + (strcmp(ptr->dst, "/") == 0)) + len = ptr->slen + 1; + else + len = ptr->slen; + if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0) + return NULL; + return dst; + } + } + ptr = ptr->next; + } + return NULL; +} + +struct selabel_sub *selabel_subs_init(const char *path, + struct selabel_sub *list, + struct selabel_digest *digest) +{ + char buf[1024]; + FILE *cfg = fopen(path, "r"); + struct selabel_sub *sub = NULL; + struct stat sb; + + if (!cfg) + return list; + + if (fstat(fileno(cfg), &sb) < 0) + return list; + + while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { + char *ptr = NULL; + char *src = buf; + char *dst = NULL; + + while (*src && isspace(*src)) + src++; + if (src[0] == '#') continue; + ptr = src; + while (*ptr && ! isspace(*ptr)) + ptr++; + *ptr++ = '\0'; + if (! *src) continue; + + dst = ptr; + while (*dst && isspace(*dst)) + dst++; + ptr=dst; + while (*ptr && ! isspace(*ptr)) + ptr++; + *ptr='\0'; + if (! *dst) + continue; + + sub = malloc(sizeof(*sub)); + if (! sub) + goto err; + memset(sub, 0, sizeof(*sub)); + + sub->src=strdup(src); + if (! sub->src) + goto err; + + sub->dst=strdup(dst); + if (! sub->dst) + goto err; + + sub->slen = strlen(src); + sub->next = list; + list = sub; + } + + if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0) + goto err; + +out: + fclose(cfg); + return list; +err: + if (sub) + free(sub->src); + free(sub); + goto out; +} + +static inline struct selabel_digest *selabel_is_digest_set + (const struct selinux_opt *opts, + unsigned n, + struct selabel_digest *entry) +{ + struct selabel_digest *digest = NULL; + + while (n--) { + if (opts[n].type == SELABEL_OPT_DIGEST && + opts[n].value == (char *)1) { + digest = calloc(1, sizeof(*digest)); + if (!digest) + goto err; + + digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1); + if (!digest->digest) + goto err; + + digest->specfile_list = calloc(DIGEST_FILES_MAX, + sizeof(char *)); + if (!digest->specfile_list) + goto err; + + entry = digest; + return entry; + } + } + return NULL; + +err: + free(digest->digest); + free(digest->specfile_list); + free(digest); + return NULL; +} + +static void selabel_digest_fini(struct selabel_digest *ptr) +{ + int i; + + free(ptr->digest); + free(ptr->hashbuf); + + if (ptr->specfile_list) { + for (i = 0; ptr->specfile_list[i]; i++) + free(ptr->specfile_list[i]); + free(ptr->specfile_list); + } + free(ptr); +} + +/* + * Validation functions + */ + +static inline int selabel_is_validate_set(const struct selinux_opt *opts, + unsigned n) +{ + while (n--) + if (opts[n].type == SELABEL_OPT_VALIDATE) + return !!opts[n].value; + + return 0; +} + +int selabel_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts) +{ + int rc = 0; + + if (!rec->validating || contexts->validated) + goto out; + + rc = selinux_validate(&contexts->ctx_raw); + if (rc < 0) + goto out; + + contexts->validated = 1; +out: + return rc; +} + +/* Public API helpers */ +static char *selabel_sub_key(struct selabel_handle *rec, const char *key) +{ + char *ptr = NULL; + char *dptr = NULL; + + ptr = selabel_sub(rec->subs, key); + if (ptr) { + dptr = selabel_sub(rec->dist_subs, ptr); + if (dptr) { + free(ptr); + ptr = dptr; + } + } else { + ptr = selabel_sub(rec->dist_subs, key); + } + if (ptr) + return ptr; + + return NULL; +} + +static int selabel_fini(struct selabel_handle *rec, + struct selabel_lookup_rec *lr, + int translating) +{ + if (compat_validate(rec, lr, rec->spec_file, 0)) + return -1; + + if (translating && !lr->ctx_trans && + selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) + return -1; + + return 0; +} + +static struct selabel_lookup_rec * +selabel_lookup_common(struct selabel_handle *rec, int translating, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + char *ptr = NULL; + + if (key == NULL) { + errno = EINVAL; + return NULL; + } + + ptr = selabel_sub_key(rec, key); + if (ptr) { + lr = rec->func_lookup(rec, ptr, type); + free(ptr); + } else { + lr = rec->func_lookup(rec, key, type); + } + if (!lr) + return NULL; + + if (selabel_fini(rec, lr, translating)) + return NULL; + + return lr; +} + +static struct selabel_lookup_rec * +selabel_lookup_bm_common(struct selabel_handle *rec, int translating, + const char *key, int type, const char **aliases) +{ + struct selabel_lookup_rec *lr; + char *ptr = NULL; + + if (key == NULL) { + errno = EINVAL; + return NULL; + } + + ptr = selabel_sub_key(rec, key); + if (ptr) { + lr = rec->func_lookup_best_match(rec, ptr, aliases, type); + free(ptr); + } else { + lr = rec->func_lookup_best_match(rec, key, aliases, type); + } + if (!lr) + return NULL; + + if (selabel_fini(rec, lr, translating)) + return NULL; + + return lr; +} + +/* + * Public API + */ + +struct selabel_handle *selabel_open(unsigned int backend, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct selabel_handle *rec = NULL; + + if (backend >= ARRAY_SIZE(initfuncs)) { + errno = EINVAL; + goto out; + } + + rec = (struct selabel_handle *)malloc(sizeof(*rec)); + if (!rec) + goto out; + + memset(rec, 0, sizeof(*rec)); + rec->backend = backend; + rec->validating = selabel_is_validate_set(opts, nopts); + + rec->subs = NULL; + rec->dist_subs = NULL; + rec->digest = selabel_is_digest_set(opts, nopts, rec->digest); + + if ((*initfuncs[backend])(rec, opts, nopts)) { + free(rec->spec_file); + free(rec); + rec = NULL; + } + +out: + return rec; +} + +int selabel_lookup(struct selabel_handle *rec, char **con, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + + lr = selabel_lookup_common(rec, 1, key, type); + if (!lr) + return -1; + + *con = strdup(lr->ctx_trans); + return *con ? 0 : -1; +} + +int selabel_lookup_raw(struct selabel_handle *rec, char **con, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + + lr = selabel_lookup_common(rec, 0, key, type); + if (!lr) + return -1; + + *con = strdup(lr->ctx_raw); + return *con ? 0 : -1; +} + +bool selabel_partial_match(struct selabel_handle *rec, const char *key) +{ + char *ptr; + bool ret; + + if (!rec->func_partial_match) { + /* + * If the label backend does not support partial matching, + * then assume a match is possible. + */ + return true; + } + + ptr = selabel_sub_key(rec, key); + if (ptr) { + ret = rec->func_partial_match(rec, ptr); + free(ptr); + } else { + ret = rec->func_partial_match(rec, key); + } + + return ret; +} + +int selabel_lookup_best_match(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type) +{ + struct selabel_lookup_rec *lr; + + if (!rec->func_lookup_best_match) { + errno = ENOTSUP; + return -1; + } + + lr = selabel_lookup_bm_common(rec, 1, key, type, aliases); + if (!lr) + return -1; + + *con = strdup(lr->ctx_trans); + return *con ? 0 : -1; +} + +int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type) +{ + struct selabel_lookup_rec *lr; + + if (!rec->func_lookup_best_match) { + errno = ENOTSUP; + return -1; + } + + lr = selabel_lookup_bm_common(rec, 0, key, type, aliases); + if (!lr) + return -1; + + *con = strdup(lr->ctx_raw); + return *con ? 0 : -1; +} + +enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, + struct selabel_handle *h2) +{ + if (!h1->func_cmp || h1->func_cmp != h2->func_cmp) + return SELABEL_INCOMPARABLE; + + return h1->func_cmp(h1, h2); +} + +int selabel_digest(struct selabel_handle *rec, + unsigned char **digest, size_t *digest_len, + char ***specfiles, size_t *num_specfiles) +{ + if (!rec->digest) { + errno = EINVAL; + return -1; + } + + *digest = rec->digest->digest; + *digest_len = DIGEST_SPECFILE_SIZE; + *specfiles = rec->digest->specfile_list; + *num_specfiles = rec->digest->specfile_cnt; + return 0; +} + +void selabel_close(struct selabel_handle *rec) +{ + selabel_subs_fini(rec->subs); + selabel_subs_fini(rec->dist_subs); + if (rec->digest) + selabel_digest_fini(rec->digest); + rec->func_close(rec); + free(rec->spec_file); + free(rec); +} + +void selabel_stats(struct selabel_handle *rec) +{ + rec->func_stats(rec); +}
diff --git a/selinux/libselinux/src/label_android_property.c b/selinux/libselinux/src/label_android_property.c new file mode 100644 index 0000000..290b438 --- /dev/null +++ b/selinux/libselinux/src/label_android_property.c
@@ -0,0 +1,304 @@ +/* + * Property Service contexts backend for labeling Android + * property keys + */ + +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "callbacks.h" +#include "label_internal.h" + +/* A property security context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *property_key; /* property key string */ +} spec_t; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications is sorted for longest + * prefix match + */ + spec_t *spec_arr; + unsigned int nspec; /* total number of specifications */ +}; + +static int cmp(const void *A, const void *B) +{ + const struct spec *sp1 = A, *sp2 = B; + + if (strncmp(sp1->property_key, "*", 1) == 0) + return 1; + if (strncmp(sp2->property_key, "*", 1) == 0) + return -1; + + size_t L1 = strlen(sp1->property_key); + size_t L2 = strlen(sp2->property_key); + + return (L1 < L2) - (L1 > L2); +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if (!strcmp(spec_arr[jj].property_key, + curr_spec->property_key)) { + rc = -1; + errno = EINVAL; + if (strcmp(spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + selinux_log + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->property_key, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + selinux_log + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->property_key); + } + } + } + } + return rc; +} + +static int process_line(struct selabel_handle *rec, + const char *path, char *line_buf, + int pass, unsigned lineno) +{ + int items; + char *prop = NULL, *context = NULL; + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int nspec = data->nspec; + const char *errbuf = NULL; + + items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); + if (items < 0) { + items = errno; + selinux_log(SELINUX_ERROR, + "%s: line %u error due to: %s\n", path, + lineno, errbuf ?: strerror(errno)); + errno = items; + return -1; + } + + if (items == 0) + return items; + + if (items != 2) { + selinux_log(SELINUX_ERROR, + "%s: line %u is missing fields\n", path, + lineno); + free(prop); + errno = EINVAL; + return -1; + } + + if (pass == 0) { + free(prop); + free(context); + } else if (pass == 1) { + /* On the second pass, process and store the specification in spec. */ + spec_arr[nspec].property_key = prop; + spec_arr[nspec].lr.ctx_raw = context; + + if (rec->validating) { + if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { + selinux_log(SELINUX_ERROR, + "%s: line %u has invalid context %s\n", + path, lineno, spec_arr[nspec].lr.ctx_raw); + errno = EINVAL; + return -1; + } + } + } + + data->nspec = ++nspec; + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + FILE *fp; + char line_buf[BUFSIZ]; + unsigned int lineno, maxnspec, pass; + int status = -1; + struct stat sb; + + /* Process arguments */ + while (n--) + switch (opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + if (!path) + return -1; + + /* Open the specification file. */ + if ((fp = fopen(path, "r")) == NULL) + return -1; + + if (fstat(fileno(fp), &sb) < 0) + goto finish; + errno = EINVAL; + if (!S_ISREG(sb.st_mode)) + goto finish; + + /* + * Two passes of the specification file. First is to get the size. + * After the first pass, the spec array is malloced to the appropriate + * size. Second pass is to populate the spec array and check for + * dups. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + data->nspec = 0; + lineno = 0; + + while (fgets(line_buf, sizeof(line_buf) - 1, fp) + && data->nspec < maxnspec) { + if (process_line(rec, path, line_buf, pass, ++lineno) + != 0) + goto finish; + } + + if (pass == 1) { + status = nodups_specs(data, path); + + if (status) + goto finish; + } + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + + if (NULL == (data->spec_arr = + malloc(sizeof(spec_t) * data->nspec))) + goto finish; + + memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + + qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->property_key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (data->spec_arr) + free(data->spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, + int __attribute__((unused)) type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + struct selabel_lookup_rec *ret = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + for (i = 0; i < data->nspec; i++) { + if (strncmp(spec_arr[i].property_key, key, + strlen(spec_arr[i].property_key)) == 0) { + break; + } + if (strncmp(spec_arr[i].property_key, "*", 1) == 0) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + ret = &spec_arr[i].lr; + +finish: + return ret; +} + +static void stats(struct selabel_handle __attribute__((unused)) *rec) +{ + selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); +} + +int selabel_property_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &lookup; + + return init(rec, opts, nopts); +}
diff --git a/selinux/libselinux/src/label_db.c b/selinux/libselinux/src/label_db.c new file mode 100644 index 0000000..1155bcc --- /dev/null +++ b/selinux/libselinux/src/label_db.c
@@ -0,0 +1,356 @@ +/* + * Media contexts backend for DB objects + * + * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> + */ + +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <fnmatch.h> +#include "callbacks.h" +#include "label_internal.h" + +/* + * Regular database object's security context interface + * + * It provides applications a regular security context for the given + * database objects. The pair of object's name and a security context + * are described in the specfile. In the default, it shall be stored + * in the /etc/selinux/$POLICYTYPE/contexts/sepgsql_contexts . + * (It assumes SE-PostgreSQL in the default. For other RDBMS, use the + * SELABEL_OPT_PATH option to specify different specfile.) + * + * Each line has the following format: + * <object class> <object name/identifier> <security context> + * + * For example: + * ---------------------------------------- + * # + * # It is an example specfile for database obejcts + * # + * db_database template1 system_u:object_r:sepgsql_db_t:s0 + * + * db_schema *.pg_catalog system_u:object_r:sepgsql_sys_schema_t:s0 + * + * db_table *.pg_catalog.* system_u:object_r:sepgsql_sysobj_t:s0 + * db_column *.pg_catalog.*.* system_u:object_r:sepgsql_sysobj_t:s0 + * ---------------------------------------- + * + * All the characters after the '#' are dealt as comments. + * + * The first token is object class. SELABEL_DB_* declared in label.h are + * corresponding to a certain database object. + * + * The object name/identifier is compared to the given key. + * A database object can have its own namespace hierarchy. + * In the case of SE-PgSQL, database is the top level object, and schema + * is deployed just under a database. A schema can contains various kind + * of objects, such as tables, procedures and so on. + * Thus, when we lookup an expected security context for a table of + * "pg_class", it is necessary to assume selabel_lookup() is called with + * "postgres.pg_catalog.pg_class", not just a "pg_class". + * + * Wildcards ('*' or '?') are available on the patterns, so if you want + * to match a table within any schema, you should set '*' on the upper + * namespaces of the table. + * + * The structure of namespace depends on RDBMS. + * For example, Trusted-RUBIX has an idea of "catalog" which performs + * as a namespace between a database and individual schemas. In this + * case, a table has upper three layers. + */ + +/* + * spec_t : It holds a pair of a key and an expected security context + */ +typedef struct spec { + struct selabel_lookup_rec lr; + char *key; + int type; + int matches; +} spec_t; + +/* + * catalog_t : An array of spec_t + */ +typedef struct catalog { + unsigned int nspec; /* number of specs in use */ + unsigned int limit; /* physical limitation of specs[] */ + spec_t specs[0]; +} catalog_t; + +/* + * Helper function to parse a line read from the specfile + */ +static int +process_line(const char *path, char *line_buf, unsigned int line_num, + catalog_t *catalog) +{ + spec_t *spec = &catalog->specs[catalog->nspec]; + char *type, *key, *context, *temp; + int items; + + /* Cut off comments */ + temp = strchr(line_buf, '#'); + if (temp) + *temp = '\0'; + + /* + * Every entry must have the following format + * <object class> <object name> <security context> + */ + type = key = context = temp = NULL; + items = sscanf(line_buf, "%ms %ms %ms %ms", + &type, &key, &context, &temp); + if (items != 3) { + if (items > 0) + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid format, skipped", + path, line_num); + goto skip; + } + + /* + * Set up individual spec entry + */ + memset(spec, 0, sizeof(spec_t)); + + if (!strcmp(type, "db_database")) + spec->type = SELABEL_DB_DATABASE; + else if (!strcmp(type, "db_schema")) + spec->type = SELABEL_DB_SCHEMA; + else if (!strcmp(type, "db_table")) + spec->type = SELABEL_DB_TABLE; + else if (!strcmp(type, "db_column")) + spec->type = SELABEL_DB_COLUMN; + else if (!strcmp(type, "db_sequence")) + spec->type = SELABEL_DB_SEQUENCE; + else if (!strcmp(type, "db_view")) + spec->type = SELABEL_DB_VIEW; + else if (!strcmp(type, "db_procedure")) + spec->type = SELABEL_DB_PROCEDURE; + else if (!strcmp(type, "db_blob")) + spec->type = SELABEL_DB_BLOB; + else if (!strcmp(type, "db_tuple")) + spec->type = SELABEL_DB_TUPLE; + else if (!strcmp(type, "db_language")) + spec->type = SELABEL_DB_LANGUAGE; + else if (!strcmp(type, "db_exception")) + spec->type = SELABEL_DB_EXCEPTION; + else if (!strcmp(type, "db_datatype")) + spec->type = SELABEL_DB_DATATYPE; + else { + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid object type %s\n", + path, line_num, type); + goto skip; + } + + free(type); + spec->key = key; + spec->lr.ctx_raw = context; + + catalog->nspec++; + + return 0; + +skip: + free(type); + free(key); + free(context); + free(temp); + + return 0; +} + +/* + * selabel_close() handler + */ +static void +db_close(struct selabel_handle *rec) +{ + catalog_t *catalog = (catalog_t *)rec->data; + spec_t *spec; + unsigned int i; + + for (i = 0; i < catalog->nspec; i++) { + spec = &catalog->specs[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + free(catalog); +} + +/* + * selabel_lookup() handler + */ +static struct selabel_lookup_rec * +db_lookup(struct selabel_handle *rec, const char *key, int type) +{ + catalog_t *catalog = (catalog_t *)rec->data; + spec_t *spec; + unsigned int i; + + for (i = 0; i < catalog->nspec; i++) { + spec = &catalog->specs[i]; + + if (spec->type != type) + continue; + if (!fnmatch(spec->key, key, 0)) { + spec->matches++; + + return &spec->lr; + } + } + + /* No found */ + errno = ENOENT; + return NULL; +} + +/* + * selabel_stats() handler + */ +static void +db_stats(struct selabel_handle *rec) +{ + catalog_t *catalog = (catalog_t *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < catalog->nspec; i++) + total += catalog->specs[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + catalog->nspec, total); +} + +/* + * selabel_open() handler + */ +static catalog_t * +db_init(const struct selinux_opt *opts, unsigned nopts, + struct selabel_handle *rec) +{ + catalog_t *catalog; + FILE *filp; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + unsigned int line_num = 0; + unsigned int i; + struct stat sb; + + /* + * Initialize catalog data structure + */ + catalog = malloc(sizeof(catalog_t) + 32 * sizeof(spec_t)); + if (!catalog) + return NULL; + catalog->limit = 32; + catalog->nspec = 0; + + /* + * Process arguments + * + * SELABEL_OPT_PATH: + * It allows to specify an alternative specification file instead of + * the default one. If RDBMS is not SE-PostgreSQL, it may need to + * specify an explicit specfile for database objects. + */ + while (nopts--) { + switch (opts[nopts].type) { + case SELABEL_OPT_PATH: + path = opts[nopts].value; + break; + } + } + + /* + * Open the specification file + */ + if (!path) + path = selinux_sepgsql_context_path(); + + if ((filp = fopen(path, "rb")) == NULL) { + free(catalog); + return NULL; + } + if (fstat(fileno(filp), &sb) < 0) + return NULL; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return NULL; + } + rec->spec_file = strdup(path); + + /* + * Parse for each lines + */ + while (getline(&line_buf, &line_len, filp) > 0) { + /* + * Expand catalog array, if necessary + */ + if (catalog->limit == catalog->nspec) { + size_t length; + unsigned int new_limit = 2 * catalog->limit; + catalog_t *new_catalog; + + length = sizeof(catalog_t) + + new_limit * sizeof(spec_t); + new_catalog = realloc(catalog, length); + if (!new_catalog) + goto out_error; + + catalog = new_catalog; + catalog->limit = new_limit; + } + + /* + * Parse a line + */ + if (process_line(path, line_buf, ++line_num, catalog) < 0) + goto out_error; + } + free(line_buf); + + if (digest_add_specfile(rec->digest, filp, NULL, sb.st_size, path) < 0) + goto out_error; + + digest_gen_hash(rec->digest); + + fclose(filp); + + return catalog; + +out_error: + for (i = 0; i < catalog->nspec; i++) { + spec_t *spec = &catalog->specs[i]; + + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + free(catalog); + + return NULL; +} + +/* + * Initialize selabel_handle and load the entries of specfile + */ +int selabel_db_init(struct selabel_handle *rec, + const struct selinux_opt *opts, unsigned nopts) +{ + rec->func_close = &db_close; + rec->func_lookup = &db_lookup; + rec->func_stats = &db_stats; + rec->data = db_init(opts, nopts, rec); + + return !rec->data ? -1 : 0; +}
diff --git a/selinux/libselinux/src/label_file.c b/selinux/libselinux/src/label_file.c new file mode 100644 index 0000000..071d902 --- /dev/null +++ b/selinux/libselinux/src/label_file.c
@@ -0,0 +1,941 @@ +/* + * File contexts backend for labeling system + * + * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> + * Author : Stephen Smalley <sds@tycho.nsa.gov> + */ + +#include <assert.h> +#include <fcntl.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <pcre.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "callbacks.h" +#include "label_internal.h" +#include "label_file.h" + +/* + * Internals, mostly moved over from matchpathcon.c + */ + +/* return the length of the text that is the stem of a file name */ +static int get_stem_from_file_name(const char *const buf) +{ + const char *tmp = strchr(buf + 1, '/'); + + if (!tmp) + return 0; + return tmp - buf; +} + +/* find the stem of a file name, returns the index into stem_arr (or -1 if + * there is no match - IE for a file in the root directory or a regex that is + * too complex for us). Makes buf point to the text AFTER the stem. */ +static int find_stem_from_file(struct saved_data *data, const char **buf) +{ + int i; + int stem_len = get_stem_from_file_name(*buf); + + if (!stem_len) + return -1; + for (i = 0; i < data->num_stems; i++) { + if (stem_len == data->stem_arr[i].len + && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) { + *buf += stem_len; + return i; + } + } + return -1; +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if ((!strcmp(spec_arr[jj].regex_str, + curr_spec->regex_str)) + && (!spec_arr[jj].mode || !curr_spec->mode + || spec_arr[jj].mode == curr_spec->mode)) { + rc = -1; + errno = EINVAL; + if (strcmp(spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + COMPAT_LOG + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->regex_str, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + COMPAT_LOG + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->regex_str); + } + } + } + } + return rc; +} + +static int load_mmap(struct selabel_handle *rec, const char *path, + struct stat *sb, bool isbinary, + struct selabel_digest *digest) +{ + struct saved_data *data = (struct saved_data *)rec->data; + char mmap_path[PATH_MAX + 1]; + int mmapfd; + int rc; + struct stat mmap_stat; + char *addr, *str_buf; + size_t len; + int *stem_map; + struct mmap_area *mmap_area; + uint32_t i, magic, version; + uint32_t entry_len, stem_map_len, regex_array_len; + + if (isbinary) { + len = strlen(path); + if (len >= sizeof(mmap_path)) + return -1; + strcpy(mmap_path, path); + } else { + rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); + if (rc >= (int)sizeof(mmap_path)) + return -1; + } + + mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC); + if (mmapfd < 0) + return -1; + + rc = fstat(mmapfd, &mmap_stat); + if (rc < 0) { + close(mmapfd); + return -1; + } + + /* if mmap is old, ignore it */ + if (mmap_stat.st_mtime < sb->st_mtime) { + close(mmapfd); + return -1; + } + + /* ok, read it in... */ + len = mmap_stat.st_size; + len += (sysconf(_SC_PAGE_SIZE) - 1); + len &= ~(sysconf(_SC_PAGE_SIZE) - 1); + + mmap_area = malloc(sizeof(*mmap_area)); + if (!mmap_area) { + close(mmapfd); + return -1; + } + + addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); + close(mmapfd); + if (addr == MAP_FAILED) { + free(mmap_area); + perror("mmap"); + return -1; + } + + /* save where we mmap'd the file to cleanup on close() */ + mmap_area->addr = mmap_area->next_addr = addr; + mmap_area->len = mmap_area->next_len = len; + mmap_area->next = data->mmap_areas; + data->mmap_areas = mmap_area; + + /* check if this looks like an fcontext file */ + rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); + if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) + return -1; + + /* check if this version is higher than we understand */ + rc = next_entry(&version, mmap_area, sizeof(uint32_t)); + if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) + return -1; + + if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { + len = strlen(pcre_version()); + + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0) + return -1; + + /* Check version lengths */ + if (len != entry_len) + return -1; + + /* Check if pcre version mismatch */ + str_buf = malloc(entry_len + 1); + if (!str_buf) + return -1; + + rc = next_entry(str_buf, mmap_area, entry_len); + if (rc < 0) { + free(str_buf); + return -1; + } + + str_buf[entry_len] = '\0'; + if ((strcmp(str_buf, pcre_version()) != 0)) { + free(str_buf); + return -1; + } + free(str_buf); + } + + /* allocate the stems_data array */ + rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !stem_map_len) + return -1; + + /* + * map indexed by the stem # in the mmap file and contains the stem + * number in the data stem_arr + */ + stem_map = calloc(stem_map_len, sizeof(*stem_map)); + if (!stem_map) + return -1; + + for (i = 0; i < stem_map_len; i++) { + char *buf; + uint32_t stem_len; + int newid; + + /* the length does not inlude the nul */ + rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !stem_len) { + rc = -1; + goto err; + } + + /* Check for stem_len wrap around. */ + if (stem_len < UINT32_MAX) { + buf = (char *)mmap_area->next_addr; + /* Check if over-run before null check. */ + rc = next_entry(NULL, mmap_area, (stem_len + 1)); + if (rc < 0) + goto err; + + if (buf[stem_len] != '\0') { + rc = -1; + goto err; + } + } else { + rc = -1; + goto err; + } + + /* store the mapping between old and new */ + newid = find_stem(data, buf, stem_len); + if (newid < 0) { + newid = store_stem(data, buf, stem_len); + if (newid < 0) { + rc = newid; + goto err; + } + data->stem_arr[newid].from_mmap = 1; + } + stem_map[i] = newid; + } + + /* allocate the regex array */ + rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !regex_array_len) { + rc = -1; + goto err; + } + + for (i = 0; i < regex_array_len; i++) { + struct spec *spec; + int32_t stem_id, meta_chars; + uint32_t mode = 0, prefix_len = 0; + + rc = grow_specs(data); + if (rc < 0) + goto err; + + spec = &data->spec_arr[data->nspec]; + spec->from_mmap = 1; + spec->regcomp = 1; + + /* Process context */ + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto err; + } + + str_buf = malloc(entry_len); + if (!str_buf) { + rc = -1; + goto err; + } + rc = next_entry(str_buf, mmap_area, entry_len); + if (rc < 0) + goto err; + + if (str_buf[entry_len - 1] != '\0') { + free(str_buf); + rc = -1; + goto err; + } + spec->lr.ctx_raw = str_buf; + + if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { + if (selabel_validate(rec, &spec->lr) < 0) { + selinux_log(SELINUX_ERROR, + "%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw); + goto err; + } + } + + /* Process regex string */ + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto err; + } + + spec->regex_str = (char *)mmap_area->next_addr; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + if (spec->regex_str[entry_len - 1] != '\0') { + rc = -1; + goto err; + } + + /* Process mode */ + if (version >= SELINUX_COMPILED_FCONTEXT_MODE) + rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); + else + rc = next_entry(&mode, mmap_area, sizeof(mode_t)); + if (rc < 0) + goto err; + + spec->mode = mode; + + /* map the stem id from the mmap file to the data->stem_arr */ + rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); + if (rc < 0) + goto err; + + if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) + spec->stem_id = -1; + else + spec->stem_id = stem_map[stem_id]; + + /* retrieve the hasMetaChars bit */ + rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); + if (rc < 0) + goto err; + + spec->hasMetaChars = meta_chars; + /* and prefix length for use by selabel_lookup_best_match */ + if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { + rc = next_entry(&prefix_len, mmap_area, + sizeof(uint32_t)); + if (rc < 0) + goto err; + + spec->prefix_len = prefix_len; + } + + /* Process regex and study_data entries */ + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto err; + } + spec->regex = (pcre *)mmap_area->next_addr; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + /* Check that regex lengths match. pcre_fullinfo() + * also validates its magic number. */ + rc = pcre_fullinfo(spec->regex, NULL, PCRE_INFO_SIZE, &len); + if (rc < 0 || len != entry_len) { + rc = -1; + goto err; + } + + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto err; + } + spec->lsd.study_data = (void *)mmap_area->next_addr; + spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + /* Check that study data lengths match. */ + rc = pcre_fullinfo(spec->regex, &spec->lsd, + PCRE_INFO_STUDYSIZE, &len); + if (rc < 0 || len != entry_len) { + rc = -1; + goto err; + } + + data->nspec++; + } + + rc = digest_add_specfile(digest, NULL, addr, mmap_stat.st_size, + mmap_path); + if (rc) + goto err; + +err: + free(stem_map); + + return rc; +} + +static int process_file(const char *path, const char *suffix, + struct selabel_handle *rec, + const char *prefix, struct selabel_digest *digest) +{ + FILE *fp; + struct stat sb; + unsigned int lineno; + size_t line_len = 0; + char *line_buf = NULL; + int rc; + char stack_path[PATH_MAX + 1]; + bool isbinary = false; + uint32_t magic; + + /* append the path suffix if we have one */ + if (suffix) { + rc = snprintf(stack_path, sizeof(stack_path), + "%s.%s", path, suffix); + if (rc >= (int)sizeof(stack_path)) { + errno = ENAMETOOLONG; + return -1; + } + path = stack_path; + } + + /* Open the specification file. */ + fp = fopen(path, "r"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + + magic = 0; + if (fread(&magic, sizeof magic, 1, fp) != 1) { + if (ferror(fp)) { + errno = EINVAL; + fclose(fp); + return -1; + } + clearerr(fp); + } + + if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) { + /* file_contexts.bin format */ + fclose(fp); + fp = NULL; + isbinary = true; + } else { + rewind(fp); + } + } else { + /* + * Text file does not exist, so clear the timestamp + * so that we will always pass the timestamp comparison + * with the bin file in load_mmap(). + */ + sb.st_mtime = 0; + } + + rc = load_mmap(rec, path, &sb, isbinary, digest); + if (rc == 0) + goto out; + + if (!fp) + return -1; /* no text or bin file */ + + /* + * Then do detailed validation of the input and fill the spec array + */ + lineno = 0; + rc = 0; + while (getline(&line_buf, &line_len, fp) > 0) { + rc = process_line(rec, path, prefix, line_buf, ++lineno); + if (rc) + goto out; + } + + rc = digest_add_specfile(digest, fp, NULL, sb.st_size, path); + +out: + free(line_buf); + if (fp) + fclose(fp); + return rc; +} + +static void closef(struct selabel_handle *rec); + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + const char *prefix = NULL; + char subs_file[PATH_MAX + 1]; + int status = -1, baseonly = 0; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + case SELABEL_OPT_SUBSET: + prefix = opts[n].value; + break; + case SELABEL_OPT_BASEONLY: + baseonly = !!opts[n].value; + break; + } + + /* Process local and distribution substitution files */ + if (!path) { + rec->dist_subs = + selabel_subs_init(selinux_file_context_subs_dist_path(), + rec->dist_subs, rec->digest); + rec->subs = selabel_subs_init(selinux_file_context_subs_path(), + rec->subs, rec->digest); + path = selinux_file_context_path(); + } else { + snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path); + rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs, + rec->digest); + snprintf(subs_file, sizeof(subs_file), "%s.subs", path); + rec->subs = selabel_subs_init(subs_file, rec->subs, + rec->digest); + } + + rec->spec_file = strdup(path); + + /* + * The do detailed validation of the input and fill the spec array + */ + status = process_file(path, NULL, rec, prefix, rec->digest); + if (status) + goto finish; + + if (rec->validating) { + status = nodups_specs(data, path); + if (status) + goto finish; + } + + if (!baseonly) { + status = process_file(path, "homedirs", rec, prefix, + rec->digest); + if (status && errno != ENOENT) + goto finish; + + status = process_file(path, "local", rec, prefix, + rec->digest); + if (status && errno != ENOENT) + goto finish; + } + + digest_gen_hash(rec->digest); + + status = sort_specs(data); + +finish: + if (status) + closef(rec); + + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct mmap_area *area, *last_area; + struct spec *spec; + struct stem *stem; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->lr.ctx_trans); + free(spec->lr.ctx_raw); + if (spec->from_mmap) + continue; + free(spec->regex_str); + free(spec->type_str); + if (spec->regcomp) { + pcre_free(spec->regex); + pcre_free_study(spec->sd); + } + } + + for (i = 0; i < (unsigned int)data->num_stems; i++) { + stem = &data->stem_arr[i]; + if (stem->from_mmap) + continue; + free(stem->buf); + } + + if (data->spec_arr) + free(data->spec_arr); + if (data->stem_arr) + free(data->stem_arr); + + area = data->mmap_areas; + while (area) { + munmap(area->addr, area->len); + last_area = area; + area = area->next; + free(last_area); + } + free(data); +} + +static struct spec *lookup_common(struct selabel_handle *rec, + const char *key, + int type, + bool partial) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec_arr = data->spec_arr; + int i, rc, file_stem, pcre_options = 0; + mode_t mode = (mode_t)type; + const char *buf; + struct spec *ret = NULL; + char *clean_key = NULL; + const char *prev_slash, *next_slash; + unsigned int sofar = 0; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + /* Remove duplicate slashes */ + if ((next_slash = strstr(key, "//"))) { + clean_key = (char *) malloc(strlen(key) + 1); + if (!clean_key) + goto finish; + prev_slash = key; + while (next_slash) { + memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash); + sofar += next_slash - prev_slash; + prev_slash = next_slash + 1; + next_slash = strstr(prev_slash, "//"); + } + strcpy(clean_key + sofar, prev_slash); + key = clean_key; + } + + buf = key; + file_stem = find_stem_from_file(data, &buf); + mode &= S_IFMT; + + if (partial) + pcre_options |= PCRE_PARTIAL_SOFT; + + /* + * Check for matching specifications in reverse order, so that + * the last matching specification is used. + */ + for (i = data->nspec - 1; i >= 0; i--) { + struct spec *spec = &spec_arr[i]; + /* if the spec in question matches no stem or has the same + * stem as the file AND if the spec in question has no mode + * specified or if the mode matches the file mode then we do + * a regex check */ + if ((spec->stem_id == -1 || spec->stem_id == file_stem) && + (!mode || !spec->mode || mode == spec->mode)) { + if (compile_regex(data, spec, NULL) < 0) + goto finish; + if (spec->stem_id == -1) + rc = pcre_exec(spec->regex, + get_pcre_extra(spec), + key, strlen(key), 0, + pcre_options, NULL, 0); + else + rc = pcre_exec(spec->regex, + get_pcre_extra(spec), + buf, strlen(buf), 0, + pcre_options, NULL, 0); + if (rc == 0) { + spec->matches++; + break; + } else if (partial && rc == PCRE_ERROR_PARTIAL) + break; + + if (rc == PCRE_ERROR_NOMATCH) + continue; + + errno = ENOENT; + /* else it's an error */ + goto finish; + } + } + + if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + errno = 0; + ret = &spec_arr[i]; + +finish: + free(clean_key); + return ret; +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, int type) +{ + struct spec *spec; + + spec = lookup_common(rec, key, type, false); + if (spec) + return &spec->lr; + return NULL; +} + +static bool partial_match(struct selabel_handle *rec, const char *key) +{ + return lookup_common(rec, key, 0, true) ? true : false; +} + +static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec, + const char *key, + const char **aliases, + int type) +{ + size_t n, i; + int best = -1; + struct spec **specs; + size_t prefix_len = 0; + struct selabel_lookup_rec *lr = NULL; + + if (!aliases || !aliases[0]) + return lookup(rec, key, type); + + for (n = 0; aliases[n]; n++) + ; + + specs = calloc(n+1, sizeof(struct spec *)); + if (!specs) + return NULL; + specs[0] = lookup_common(rec, key, type, false); + if (specs[0]) { + if (!specs[0]->hasMetaChars) { + /* exact match on key */ + lr = &specs[0]->lr; + goto out; + } + best = 0; + prefix_len = specs[0]->prefix_len; + } + for (i = 1; i <= n; i++) { + specs[i] = lookup_common(rec, aliases[i-1], type, false); + if (specs[i]) { + if (!specs[i]->hasMetaChars) { + /* exact match on alias */ + lr = &specs[i]->lr; + goto out; + } + if (specs[i]->prefix_len > prefix_len) { + best = i; + prefix_len = specs[i]->prefix_len; + } + } + } + + if (best >= 0) { + /* longest fixed prefix match on key or alias */ + lr = &specs[best]->lr; + } else { + errno = ENOENT; + } + +out: + free(specs); + return lr; +} + +static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j) +{ + selinux_log(SELINUX_INFO, + "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", + reason, + i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, + j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); + return SELABEL_INCOMPARABLE; +} + +static enum selabel_cmp_result cmp(struct selabel_handle *h1, + struct selabel_handle *h2) +{ + struct saved_data *data1 = (struct saved_data *)h1->data; + struct saved_data *data2 = (struct saved_data *)h2->data; + unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec; + struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr; + struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr; + bool skipped1 = false, skipped2 = false; + + i = 0; + j = 0; + while (i < nspec1 && j < nspec2) { + struct spec *spec1 = &spec_arr1[i]; + struct spec *spec2 = &spec_arr2[j]; + + /* + * Because sort_specs() moves exact pathnames to the + * end, we might need to skip over additional regex + * entries that only exist in one of the configurations. + */ + if (!spec1->hasMetaChars && spec2->hasMetaChars) { + j++; + skipped2 = true; + continue; + } + + if (spec1->hasMetaChars && !spec2->hasMetaChars) { + i++; + skipped1 = true; + continue; + } + + if (spec1->regcomp && spec2->regcomp) { + size_t len1, len2; + int rc; + + rc = pcre_fullinfo(spec1->regex, NULL, PCRE_INFO_SIZE, &len1); + assert(rc == 0); + rc = pcre_fullinfo(spec2->regex, NULL, PCRE_INFO_SIZE, &len2); + assert(rc == 0); + if (len1 != len2 || + memcmp(spec1->regex, spec2->regex, len1)) + return incomp(spec1, spec2, "regex", i, j); + } else { + if (strcmp(spec1->regex_str, spec2->regex_str)) + return incomp(spec1, spec2, "regex_str", i, j); + } + + if (spec1->mode != spec2->mode) + return incomp(spec1, spec2, "mode", i, j); + + if (spec1->stem_id == -1 && spec2->stem_id != -1) + return incomp(spec1, spec2, "stem_id", i, j); + if (spec2->stem_id == -1 && spec1->stem_id != -1) + return incomp(spec1, spec2, "stem_id", i, j); + if (spec1->stem_id != -1 && spec2->stem_id != -1) { + struct stem *stem1 = &stem_arr1[spec1->stem_id]; + struct stem *stem2 = &stem_arr2[spec2->stem_id]; + if (stem1->len != stem2->len || + strncmp(stem1->buf, stem2->buf, stem1->len)) + return incomp(spec1, spec2, "stem", i, j); + } + + if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw)) + return incomp(spec1, spec2, "ctx_raw", i, j); + + i++; + j++; + } + + if ((skipped1 || i < nspec1) && !skipped2) + return SELABEL_SUPERSET; + if ((skipped2 || j < nspec2) && !skipped1) + return SELABEL_SUBSET; + if (skipped1 && skipped2) + return SELABEL_INCOMPARABLE; + return SELABEL_EQUAL; +} + + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, nspec = data->nspec; + struct spec *spec_arr = data->spec_arr; + + for (i = 0; i < nspec; i++) { + if (spec_arr[i].matches == 0) { + if (spec_arr[i].type_str) { + COMPAT_LOG(SELINUX_WARNING, + "Warning! No matches for (%s, %s, %s)\n", + spec_arr[i].regex_str, + spec_arr[i].type_str, + spec_arr[i].lr.ctx_raw); + } else { + COMPAT_LOG(SELINUX_WARNING, + "Warning! No matches for (%s, %s)\n", + spec_arr[i].regex_str, + spec_arr[i].lr.ctx_raw); + } + } + } +} + +int selabel_file_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &lookup; + rec->func_partial_match = &partial_match; + rec->func_lookup_best_match = &lookup_best_match; + rec->func_cmp = &cmp; + + return init(rec, opts, nopts); +}
diff --git a/selinux/libselinux/src/label_file.h b/selinux/libselinux/src/label_file.h new file mode 100644 index 0000000..72fed1f --- /dev/null +++ b/selinux/libselinux/src/label_file.h
@@ -0,0 +1,486 @@ +#ifndef _SELABEL_FILE_H_ +#define _SELABEL_FILE_H_ + +#include <errno.h> +#include <string.h> + +#include <sys/stat.h> + +#include "callbacks.h" +#include "label_internal.h" + +#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a + +/* Version specific changes */ +#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 +#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 +#define SELINUX_COMPILED_FCONTEXT_MODE 3 +#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 + +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS SELINUX_COMPILED_FCONTEXT_PREFIX_LEN + +/* Prior to version 8.20, libpcre did not have pcre_free_study() */ +#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20)) +#define pcre_free_study pcre_free +#endif + +/* A file security context specification. */ +struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *regex_str; /* regular expession string for diagnostics */ + char *type_str; /* type string for diagnostic messages */ + pcre *regex; /* compiled regular expression */ + union { + pcre_extra *sd; /* pointer to extra compiled stuff */ + pcre_extra lsd; /* used to hold the mmap'd version */ + }; + mode_t mode; /* mode format value */ + int matches; /* number of matching pathnames */ + int stem_id; /* indicates which stem-compression item */ + char hasMetaChars; /* regular expression has meta-chars */ + char regcomp; /* regex_str has been compiled to regex */ + char from_mmap; /* this spec is from an mmap of the data */ + size_t prefix_len; /* length of fixed path prefix */ +}; + +/* A regular expression stem */ +struct stem { + char *buf; + int len; + char from_mmap; +}; + +/* Where we map the file in during selabel_open() */ +struct mmap_area { + void *addr; /* Start addr + len used to release memory at close */ + size_t len; + void *next_addr; /* Incremented by next_entry() */ + size_t next_len; /* Decremented by next_entry() */ + struct mmap_area *next; +}; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications, initially in the same order as in + * the specification file. Sorting occurs based on hasMetaChars. + */ + struct spec *spec_arr; + unsigned int nspec; + unsigned int alloc_specs; + + /* + * The array of regular expression stems. + */ + struct stem *stem_arr; + int num_stems; + int alloc_stems; + struct mmap_area *mmap_areas; +}; + +static inline pcre_extra *get_pcre_extra(struct spec *spec) +{ + if (spec->from_mmap) + return &spec->lsd; + else + return spec->sd; +} + +static inline mode_t string_to_mode(char *mode) +{ + size_t len; + + if (!mode) + return 0; + len = strlen(mode); + if (mode[0] != '-' || len != 2) + return -1; + switch (mode[1]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case '-': + return S_IFREG; + default: + return -1; + } + /* impossible to get here */ + return 0; +} + +static inline int grow_specs(struct saved_data *data) +{ + struct spec *specs; + size_t new_specs, total_specs; + + if (data->nspec < data->alloc_specs) + return 0; + + new_specs = data->nspec + 16; + total_specs = data->nspec + new_specs; + + specs = realloc(data->spec_arr, total_specs * sizeof(*specs)); + if (!specs) { + perror("realloc"); + return -1; + } + + /* blank the new entries */ + memset(&specs[data->nspec], 0, new_specs * sizeof(*specs)); + + data->spec_arr = specs; + data->alloc_specs = total_specs; + return 0; +} + +/* Determine if the regular expression specification has any meta characters. */ +static inline void spec_hasMetaChars(struct spec *spec) +{ + char *c; + int len; + char *end; + + c = spec->regex_str; + len = strlen(spec->regex_str); + end = c + len; + + spec->hasMetaChars = 0; + spec->prefix_len = len; + + /* Look at each character in the RE specification string for a + * meta character. Return when any meta character reached. */ + while (c < end) { + switch (*c) { + case '.': + case '^': + case '$': + case '?': + case '*': + case '+': + case '|': + case '[': + case '(': + case '{': + spec->hasMetaChars = 1; + spec->prefix_len = c - spec->regex_str; + return; + case '\\': /* skip the next character */ + c++; + break; + default: + break; + + } + c++; + } +} + +/* Move exact pathname specifications to the end. */ +static inline int sort_specs(struct saved_data *data) +{ + struct spec *spec_copy; + struct spec spec; + unsigned int i; + int front, back; + size_t len = sizeof(*spec_copy); + + spec_copy = malloc(len * data->nspec); + if (!spec_copy) + return -1; + + /* first move the exact pathnames to the back */ + front = 0; + back = data->nspec - 1; + for (i = 0; i < data->nspec; i++) { + if (data->spec_arr[i].hasMetaChars) + memcpy(&spec_copy[front++], &data->spec_arr[i], len); + else + memcpy(&spec_copy[back--], &data->spec_arr[i], len); + } + + /* + * now the exact pathnames are at the end, but they are in the reverse + * order. Since 'front' is now the first of the 'exact' we can run + * that part of the array switching the front and back element. + */ + back = data->nspec - 1; + while (front < back) { + /* save the front */ + memcpy(&spec, &spec_copy[front], len); + /* move the back to the front */ + memcpy(&spec_copy[front], &spec_copy[back], len); + /* put the old front in the back */ + memcpy(&spec_copy[back], &spec, len); + front++; + back--; + } + + free(data->spec_arr); + data->spec_arr = spec_copy; + + return 0; +} + +/* Return the length of the text that can be considered the stem, returns 0 + * if there is no identifiable stem */ +static inline int get_stem_from_spec(const char *const buf) +{ + const char *tmp = strchr(buf + 1, '/'); + const char *ind; + + if (!tmp) + return 0; + + for (ind = buf; ind < tmp; ind++) { + if (strchr(".^$?*+|[({", (int)*ind)) + return 0; + } + return tmp - buf; +} + +/* + * return the stemid given a string and a length + */ +static inline int find_stem(struct saved_data *data, const char *buf, + int stem_len) +{ + int i; + + for (i = 0; i < data->num_stems; i++) { + if (stem_len == data->stem_arr[i].len && + !strncmp(buf, data->stem_arr[i].buf, stem_len)) + return i; + } + + return -1; +} + +/* returns the index of the new stored object */ +static inline int store_stem(struct saved_data *data, char *buf, int stem_len) +{ + int num = data->num_stems; + + if (data->alloc_stems == num) { + struct stem *tmp_arr; + + data->alloc_stems = data->alloc_stems * 2 + 16; + tmp_arr = realloc(data->stem_arr, + sizeof(*tmp_arr) * data->alloc_stems); + if (!tmp_arr) + return -1; + data->stem_arr = tmp_arr; + } + data->stem_arr[num].len = stem_len; + data->stem_arr[num].buf = buf; + data->stem_arr[num].from_mmap = 0; + data->num_stems++; + + return num; +} + +/* find the stem of a file spec, returns the index into stem_arr for a new + * or existing stem, (or -1 if there is no possible stem - IE for a file in + * the root directory or a regex that is too complex for us). */ +static inline int find_stem_from_spec(struct saved_data *data, const char *buf) +{ + int stem_len = get_stem_from_spec(buf); + int stemid; + char *stem; + + if (!stem_len) + return -1; + + stemid = find_stem(data, buf, stem_len); + if (stemid >= 0) + return stemid; + + /* not found, allocate a new one */ + stem = strndup(buf, stem_len); + if (!stem) + return -1; + + return store_stem(data, stem, stem_len); +} + +/* This will always check for buffer over-runs and either read the next entry + * if buf != NULL or skip over the entry (as these areas are mapped in the + * current buffer). */ +static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes) +{ + if (bytes > fp->next_len) + return -1; + + if (buf) + memcpy(buf, fp->next_addr, bytes); + + fp->next_addr = (char *)fp->next_addr + bytes; + fp->next_len -= bytes; + return 0; +} + +static inline int compile_regex(struct saved_data *data, struct spec *spec, + const char **errbuf) +{ + const char *tmperrbuf; + char *reg_buf, *anchored_regex, *cp; + struct stem *stem_arr = data->stem_arr; + size_t len; + int erroff; + + if (spec->regcomp) + return 0; /* already done */ + + /* Skip the fixed stem. */ + reg_buf = spec->regex_str; + if (spec->stem_id >= 0) + reg_buf += stem_arr[spec->stem_id].len; + + /* Anchor the regular expression. */ + len = strlen(reg_buf); + cp = anchored_regex = malloc(len + 3); + if (!anchored_regex) + return -1; + + /* Create ^...$ regexp. */ + *cp++ = '^'; + memcpy(cp, reg_buf, len); + cp += len; + *cp++ = '$'; + *cp = '\0'; + + /* Compile the regular expression. */ + spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf, + &erroff, NULL); + free(anchored_regex); + if (!spec->regex) { + if (errbuf) + *errbuf = tmperrbuf; + return -1; + } + + spec->sd = pcre_study(spec->regex, 0, &tmperrbuf); + if (!spec->sd && tmperrbuf) { + if (errbuf) + *errbuf = tmperrbuf; + return -1; + } + + /* Done. */ + spec->regcomp = 1; + + return 0; +} + +/* This service is used by label_file.c process_file() and + * utils/sefcontext_compile.c */ +static inline int process_line(struct selabel_handle *rec, + const char *path, const char *prefix, + char *line_buf, unsigned lineno) +{ + int items, len, rc; + char *regex = NULL, *type = NULL, *context = NULL; + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec_arr; + unsigned int nspec = data->nspec; + const char *errbuf = NULL; + + items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context); + if (items < 0) { + rc = errno; + selinux_log(SELINUX_ERROR, + "%s: line %u error due to: %s\n", path, + lineno, errbuf ?: strerror(errno)); + errno = rc; + return -1; + } + + if (items == 0) + return items; + + if (items < 2) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u is missing fields\n", path, + lineno); + if (items == 1) + free(regex); + errno = EINVAL; + return -1; + } else if (items == 2) { + /* The type field is optional. */ + context = type; + type = 0; + } + + len = get_stem_from_spec(regex); + if (len && prefix && strncmp(prefix, regex, len)) { + /* Stem of regex does not match requested prefix, discard. */ + free(regex); + free(type); + free(context); + return 0; + } + + rc = grow_specs(data); + if (rc) + return rc; + + spec_arr = data->spec_arr; + + /* process and store the specification in spec. */ + spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); + spec_arr[nspec].regex_str = regex; + + spec_arr[nspec].type_str = type; + spec_arr[nspec].mode = 0; + + spec_arr[nspec].lr.ctx_raw = context; + + /* + * bump data->nspecs to cause closef() to cover it in its free + * but do not bump nspec since it's used below. + */ + data->nspec++; + + if (rec->validating && + compile_regex(data, &spec_arr[nspec], &errbuf)) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u has invalid regex %s: %s\n", + path, lineno, regex, + (errbuf ? errbuf : "out of memory")); + errno = EINVAL; + return -1; + } + + if (type) { + mode_t mode = string_to_mode(type); + + if (mode == (mode_t)-1) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u has invalid file type %s\n", + path, lineno, type); + errno = EINVAL; + return -1; + } + spec_arr[nspec].mode = mode; + } + + /* Determine if specification has + * any meta characters in the RE */ + spec_hasMetaChars(&spec_arr[nspec]); + + if (strcmp(context, "<<none>>") && rec->validating) + compat_validate(rec, &spec_arr[nspec].lr, path, lineno); + + return 0; +} + +#endif /* _SELABEL_FILE_H_ */
diff --git a/selinux/libselinux/src/label_internal.h b/selinux/libselinux/src/label_internal.h new file mode 100644 index 0000000..aa48fff --- /dev/null +++ b/selinux/libselinux/src/label_internal.h
@@ -0,0 +1,145 @@ +/* + * This file describes the internal interface used by the labeler + * for calling the user-supplied memory allocation, validation, + * and locking routine. + * + * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> + */ +#ifndef _SELABEL_INTERNAL_H_ +#define _SELABEL_INTERNAL_H_ + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <selinux/selinux.h> +#include <selinux/label.h> +#include "dso.h" +#include "sha1.h" + +/* + * Installed backends + */ +int selabel_file_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_media_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_x_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_db_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_property_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; + +/* + * Labeling internal structures + */ +struct selabel_sub { + char *src; + int slen; + char *dst; + struct selabel_sub *next; +}; + +/* + * Calculate an SHA1 hash of all the files used to build the specs. + * The hash value is held in rec->digest if SELABEL_OPT_DIGEST set. To + * calculate the hash the hashbuf will hold a concatenation of all the files + * used. This is released once the value has been calculated. + */ +#define DIGEST_SPECFILE_SIZE SHA1_HASH_SIZE +#define DIGEST_FILES_MAX 8 +struct selabel_digest { + unsigned char *digest; /* SHA1 digest of specfiles */ + unsigned char *hashbuf; /* buffer to hold specfiles */ + size_t hashbuf_size; /* buffer size */ + size_t specfile_cnt; /* how many specfiles processed */ + char **specfile_list; /* and their names */ +}; + +extern int digest_add_specfile(struct selabel_digest *digest, FILE *fp, + char *from_addr, + size_t buf_len, + const char *path); +extern void digest_gen_hash(struct selabel_digest *digest); + +extern struct selabel_sub *selabel_subs_init(const char *path, + struct selabel_sub *list, + struct selabel_digest *digest); + +struct selabel_lookup_rec { + char * ctx_raw; + char * ctx_trans; + int validated; +}; + +struct selabel_handle { + /* arguments that were passed to selabel_open */ + unsigned int backend; + int validating; + + /* labeling operations */ + struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h, + const char *key, int type); + void (*func_close) (struct selabel_handle *h); + void (*func_stats) (struct selabel_handle *h); + bool (*func_partial_match) (struct selabel_handle *h, const char *key); + struct selabel_lookup_rec *(*func_lookup_best_match) + (struct selabel_handle *h, + const char *key, + const char **aliases, + int type); + enum selabel_cmp_result (*func_cmp)(struct selabel_handle *h1, + struct selabel_handle *h2); + + /* supports backend-specific state information */ + void *data; + + /* + * The main spec file used. Note for file contexts the local and/or + * homedirs could also have been used to resolve a context. + */ + char *spec_file; + + /* substitution support */ + struct selabel_sub *dist_subs; + struct selabel_sub *subs; + /* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */ + struct selabel_digest *digest; +}; + +/* + * Validation function + */ +extern int +selabel_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts) hidden; + +/* + * Compatibility support + */ +extern int myprintf_compat; +extern void __attribute__ ((format(printf, 1, 2))) +(*myprintf) (const char *fmt, ...); + +#define COMPAT_LOG(type, fmt...) if (myprintf_compat) \ + myprintf(fmt); \ + else \ + selinux_log(type, fmt); + +extern int +compat_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts, + const char *path, unsigned lineno) hidden; + +/* + * The read_spec_entries function may be used to + * replace sscanf to read entries from spec files. + */ +extern int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...); + +#endif /* _SELABEL_INTERNAL_H_ */
diff --git a/selinux/libselinux/src/label_media.c b/selinux/libselinux/src/label_media.c new file mode 100644 index 0000000..622741b --- /dev/null +++ b/selinux/libselinux/src/label_media.c
@@ -0,0 +1,226 @@ +/* + * Media contexts backend for labeling system + * + * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> + */ + +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include "callbacks.h" +#include "label_internal.h" + +/* + * Internals + */ + +/* A context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *key; /* key string */ + int matches; /* number of matches made during operation */ +} spec_t; + +struct saved_data { + unsigned int nspec; + spec_t *spec_arr; +}; + +static int process_line(const char *path, char *line_buf, int pass, + unsigned lineno, struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + int items; + char *buf_p; + char *key, *context; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == 0) + return 0; + items = sscanf(line_buf, "%ms %ms ", &key, &context); + if (items < 2) { + selinux_log(SELINUX_WARNING, + "%s: line %u is missing fields, skipping\n", path, + lineno); + if (items == 1) + free(key); + return 0; + } + + if (pass == 1) { + data->spec_arr[data->nspec].key = key; + data->spec_arr[data->nspec].lr.ctx_raw = context; + } + + data->nspec++; + if (pass == 0) { + free(key); + free(context); + } + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + FILE *fp; + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + int status = -1; + unsigned int lineno, pass, maxnspec; + struct stat sb; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + /* Open the specification file. */ + if (!path) + path = selinux_media_context_path(); + if ((fp = fopen(path, "r")) == NULL) + return -1; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + rec->spec_file = strdup(path); + + /* + * Perform two passes over the specification file. + * The first pass counts the number of specifications and + * performs simple validation of the input. At the end + * of the first pass, the spec array is allocated. + * The second pass performs detailed validation of the input + * and fills in the spec array. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + lineno = 0; + data->nspec = 0; + while (getline(&line_buf, &line_len, fp) > 0 && + data->nspec < maxnspec) { + if (process_line(path, line_buf, pass, ++lineno, rec)) + goto finish; + } + lineno = 0; + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + data->spec_arr = malloc(sizeof(spec_t)*data->nspec); + if (data->spec_arr == NULL) + goto finish; + memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + free(line_buf); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void close(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec, *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &spec_arr[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (spec_arr) + free(spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, + int type __attribute__((unused))) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + if (!strncmp(spec_arr[i].key, key, strlen(key) + 1)) + break; + if (!strncmp(spec_arr[i].key, "*", 2)) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + return NULL; + } + + spec_arr[i].matches++; + return &spec_arr[i].lr; +} + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < data->nspec; i++) + total += data->spec_arr[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + data->nspec, total); +} + +int selabel_media_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &close; + rec->func_lookup = &lookup; + rec->func_stats = &stats; + + return init(rec, opts, nopts); +}
diff --git a/selinux/libselinux/src/label_support.c b/selinux/libselinux/src/label_support.c new file mode 100644 index 0000000..26f9ef1 --- /dev/null +++ b/selinux/libselinux/src/label_support.c
@@ -0,0 +1,192 @@ +/* + * This file contains helper functions for labeling support. + * + * Author : Richard Haines <richard_c_haines@btinternet.com> + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <errno.h> +#include "label_internal.h" + +/* + * Read an entry from a spec file (e.g. file_contexts) + * entry - Buffer to allocate for the entry. + * ptr - current location of the line to be processed. + * returns - 0 on success and *entry is set to be a null + * terminated value. On Error it returns -1 and + * errno will be set. + * + */ +static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf) +{ + *entry = NULL; + char *tmp_buf = NULL; + + while (isspace(**ptr) && **ptr != '\0') + (*ptr)++; + + tmp_buf = *ptr; + *len = 0; + + while (!isspace(**ptr) && **ptr != '\0') { + if (!isascii(**ptr)) { + errno = EINVAL; + *errbuf = "Non-ASCII characters found"; + return -1; + } + (*ptr)++; + (*len)++; + } + + if (*len) { + *entry = strndup(tmp_buf, *len); + if (!*entry) + return -1; + } + + return 0; +} + +/* + * line_buf - Buffer containing the spec entries . + * errbuf - Double pointer used for passing back specific error messages. + * num_args - The number of spec parameter entries to process. + * ... - A 'char **spec_entry' for each parameter. + * returns - The number of items processed. On error, it returns -1 with errno + * set and may set errbuf to a specific error message. + * + * This function calls read_spec_entry() to do the actual string processing. + * As such, can return anything from that function as well. + */ +int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) +{ + char **spec_entry, *buf_p; + int len, rc, items, entry_len = 0; + va_list ap; + + *errbuf = NULL; + + len = strlen(line_buf); + if (line_buf[len - 1] == '\n') + line_buf[len - 1] = '\0'; + else + /* Handle case if line not \n terminated by bumping + * the len for the check below (as the line is NUL + * terminated by getline(3)) */ + len++; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == '\0') + return 0; + + /* Process the spec file entries */ + va_start(ap, num_args); + + items = 0; + while (items < num_args) { + spec_entry = va_arg(ap, char **); + + if (len - 1 == buf_p - line_buf) { + va_end(ap); + return items; + } + + rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf); + if (rc < 0) { + va_end(ap); + return rc; + } + if (entry_len) + items++; + } + va_end(ap); + return items; +} + +/* Once all the specfiles are in the hash_buf, generate the hash. */ +void hidden digest_gen_hash(struct selabel_digest *digest) +{ + Sha1Context context; + + /* If SELABEL_OPT_DIGEST not set then just return */ + if (!digest) + return; + + Sha1Initialise(&context); + Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); + Sha1Finalise(&context, (SHA1_HASH *)digest->digest); + free(digest->hashbuf); + digest->hashbuf = NULL; + return; +} + +/** + * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true + * then generate the hash. + * @digest: pointer to the selabel_digest struct + * @fp: file pointer for fread(3) or NULL if not. + * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for + * mmap(3) files). + * @buf_len: length of buffer to copy. + * @path: pointer to the specfile. + * + * Return %0 on success, -%1 with @errno set on failure. + */ +int hidden digest_add_specfile(struct selabel_digest *digest, FILE *fp, + char *from_addr, size_t buf_len, + const char *path) +{ + unsigned char *tmp_buf; + + /* If SELABEL_OPT_DIGEST not set then just return */ + if (!digest) + return 0; + + if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { + errno = EOVERFLOW; + return -1; + } + digest->hashbuf_size += buf_len; + + tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size); + if (!tmp_buf) + return -1; + + digest->hashbuf = tmp_buf; + + if (fp) { + rewind(fp); + if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len), + 1, buf_len, fp) != buf_len) + return -1; + + rewind(fp); + } else if (from_addr) { + tmp_buf = memcpy(digest->hashbuf + + (digest->hashbuf_size - buf_len), + from_addr, buf_len); + if (!tmp_buf) + return -1; + } + /* Now add path to list */ + digest->specfile_list[digest->specfile_cnt] = strdup(path); + if (!digest->specfile_list[digest->specfile_cnt]) + return -1; + + digest->specfile_cnt++; + if (digest->specfile_cnt > DIGEST_FILES_MAX) { + errno = EOVERFLOW; + return -1; + } + + return 0; +}
diff --git a/selinux/libselinux/src/label_x.c b/selinux/libselinux/src/label_x.c new file mode 100644 index 0000000..700def1 --- /dev/null +++ b/selinux/libselinux/src/label_x.c
@@ -0,0 +1,251 @@ +/* + * Media contexts backend for X contexts + * + * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> + */ + +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <fnmatch.h> +#include "callbacks.h" +#include "label_internal.h" + +/* + * Internals + */ + +/* A context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *key; /* key string */ + int type; /* type of record (prop, ext, client) */ + int matches; /* number of matches made during operation */ +} spec_t; + +struct saved_data { + unsigned int nspec; + spec_t *spec_arr; +}; + +static int process_line(const char *path, char *line_buf, int pass, + unsigned lineno, struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + int items; + char *buf_p; + char *type, *key, *context; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == 0) + return 0; + items = sscanf(line_buf, "%ms %ms %ms ", &type, &key, &context); + if (items < 3) { + selinux_log(SELINUX_WARNING, + "%s: line %u is missing fields, skipping\n", path, + lineno); + if (items > 0) + free(type); + if (items > 1) + free(key); + return 0; + } + + if (pass == 1) { + /* Convert the type string to a mode format */ + if (!strcmp(type, "property")) + data->spec_arr[data->nspec].type = SELABEL_X_PROP; + else if (!strcmp(type, "extension")) + data->spec_arr[data->nspec].type = SELABEL_X_EXT; + else if (!strcmp(type, "client")) + data->spec_arr[data->nspec].type = SELABEL_X_CLIENT; + else if (!strcmp(type, "event")) + data->spec_arr[data->nspec].type = SELABEL_X_EVENT; + else if (!strcmp(type, "selection")) + data->spec_arr[data->nspec].type = SELABEL_X_SELN; + else if (!strcmp(type, "poly_property")) + data->spec_arr[data->nspec].type = SELABEL_X_POLYPROP; + else if (!strcmp(type, "poly_selection")) + data->spec_arr[data->nspec].type = SELABEL_X_POLYSELN; + else { + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid object type %s\n", + path, lineno, type); + return 0; + } + data->spec_arr[data->nspec].key = key; + data->spec_arr[data->nspec].lr.ctx_raw = context; + free(type); + } + + data->nspec++; + if (pass == 0) { + free(type); + free(key); + free(context); + } + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + FILE *fp; + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + int status = -1; + unsigned int lineno, pass, maxnspec; + struct stat sb; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + /* Open the specification file. */ + if (!path) + path = selinux_x_context_path(); + if ((fp = fopen(path, "r")) == NULL) + return -1; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + rec->spec_file = strdup(path); + + /* + * Perform two passes over the specification file. + * The first pass counts the number of specifications and + * performs simple validation of the input. At the end + * of the first pass, the spec array is allocated. + * The second pass performs detailed validation of the input + * and fills in the spec array. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + lineno = 0; + data->nspec = 0; + while (getline(&line_buf, &line_len, fp) > 0 && + data->nspec < maxnspec) { + if (process_line(path, line_buf, pass, ++lineno, rec)) + goto finish; + } + lineno = 0; + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + data->spec_arr = malloc(sizeof(spec_t)*data->nspec); + if (data->spec_arr == NULL) + goto finish; + memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + free(line_buf); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void close(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec, *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &spec_arr[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (spec_arr) + free(spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, int type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + if (spec_arr[i].type != type) + continue; + if (!fnmatch(spec_arr[i].key, key, 0)) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + return NULL; + } + + spec_arr[i].matches++; + return &spec_arr[i].lr; +} + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < data->nspec; i++) + total += data->spec_arr[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + data->nspec, total); +} + +int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &close; + rec->func_lookup = &lookup; + rec->func_stats = &stats; + + return init(rec, opts, nopts); +}
diff --git a/selinux/libselinux/src/lgetfilecon.c b/selinux/libselinux/src/lgetfilecon.c new file mode 100644 index 0000000..478e0c6 --- /dev/null +++ b/selinux/libselinux/src/lgetfilecon.c
@@ -0,0 +1,71 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "selinux_internal.h" +#include "policy.h" + +int lgetfilecon_raw(const char *path, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = lgetxattr(path, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(lgetfilecon_raw) + +int lgetfilecon(const char *path, char ** context) +{ + int ret; + char * rcontext; + + *context = NULL; + + ret = lgetfilecon_raw(path, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + if (ret >= 0 && *context) + return strlen(*context) + 1; + return ret; +}
diff --git a/selinux/libselinux/src/libselinux.pc.in b/selinux/libselinux/src/libselinux.pc.in new file mode 100644 index 0000000..2cd04d3 --- /dev/null +++ b/selinux/libselinux/src/libselinux.pc.in
@@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/@libdir@ +includedir=@includedir@ + +Name: libselinux +Description: SELinux utility library +Version: @VERSION@ +URL: http://userspace.selinuxproject.org/ +Requires.private: libsepol libpcre +Libs: -L${libdir} -lselinux +Cflags: -I${includedir}
diff --git a/selinux/libselinux/src/load_policy.c b/selinux/libselinux/src/load_policy.c new file mode 100644 index 0000000..4f39fc7 --- /dev/null +++ b/selinux/libselinux/src/load_policy.c
@@ -0,0 +1,467 @@ +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/utsname.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include "selinux_internal.h" +#include <sepol/sepol.h> +#include <sepol/policydb.h> +#include <dlfcn.h> +#include "policy.h" +#include <limits.h> + +#ifndef MNT_DETACH +#define MNT_DETACH 2 +#endif + +int security_load_policy(void *data, size_t len) +{ + char path[PATH_MAX]; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/load", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + ret = write(fd, data, len); + close(fd); + if (ret < 0) + return -1; + return 0; +} + +hidden_def(security_load_policy) + +int load_setlocaldefs hidden = 1; + +#undef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +int selinux_mkload_policy(int preservebools) +{ + int kernvers = security_policyvers(); + int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers; + int setlocaldefs = load_setlocaldefs; + char path[PATH_MAX]; + struct stat sb; + struct utsname uts; + size_t size; + void *map, *data; + int fd, rc = -1, prot; + sepol_policydb_t *policydb; + sepol_policy_file_t *pf; + int usesepol = 0; + int (*vers_max)(void) = NULL; + int (*vers_min)(void) = NULL; + int (*policy_file_create)(sepol_policy_file_t **) = NULL; + void (*policy_file_free)(sepol_policy_file_t *) = NULL; + void (*policy_file_set_mem)(sepol_policy_file_t *, char*, size_t) = NULL; + int (*policydb_create)(sepol_policydb_t **) = NULL; + void (*policydb_free)(sepol_policydb_t *) = NULL; + int (*policydb_read)(sepol_policydb_t *, sepol_policy_file_t *) = NULL; + int (*policydb_set_vers)(sepol_policydb_t *, unsigned int) = NULL; + int (*policydb_to_image)(sepol_handle_t *, sepol_policydb_t *, void **, size_t *) = NULL; + int (*genbools_array)(void *data, size_t len, char **names, int *values, int nel) = NULL; + int (*genusers)(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen) = NULL; + int (*genbools)(void *data, size_t len, char *boolpath) = NULL; + +#ifdef SHARED + char *errormsg = NULL; + void *libsepolh = NULL; + libsepolh = dlopen("libsepol.so.1", RTLD_NOW); + if (libsepolh) { + usesepol = 1; + dlerror(); +#define DLERR() if ((errormsg = dlerror())) goto dlclose; + vers_max = dlsym(libsepolh, "sepol_policy_kern_vers_max"); + DLERR(); + vers_min = dlsym(libsepolh, "sepol_policy_kern_vers_min"); + DLERR(); + + policy_file_create = dlsym(libsepolh, "sepol_policy_file_create"); + DLERR(); + policy_file_free = dlsym(libsepolh, "sepol_policy_file_free"); + DLERR(); + policy_file_set_mem = dlsym(libsepolh, "sepol_policy_file_set_mem"); + DLERR(); + policydb_create = dlsym(libsepolh, "sepol_policydb_create"); + DLERR(); + policydb_free = dlsym(libsepolh, "sepol_policydb_free"); + DLERR(); + policydb_read = dlsym(libsepolh, "sepol_policydb_read"); + DLERR(); + policydb_set_vers = dlsym(libsepolh, "sepol_policydb_set_vers"); + DLERR(); + policydb_to_image = dlsym(libsepolh, "sepol_policydb_to_image"); + DLERR(); + genbools_array = dlsym(libsepolh, "sepol_genbools_array"); + DLERR(); + genusers = dlsym(libsepolh, "sepol_genusers"); + DLERR(); + genbools = dlsym(libsepolh, "sepol_genbools"); + DLERR(); + +#undef DLERR + } +#else + usesepol = 1; + vers_max = sepol_policy_kern_vers_max; + vers_min = sepol_policy_kern_vers_min; + policy_file_create = sepol_policy_file_create; + policy_file_free = sepol_policy_file_free; + policy_file_set_mem = sepol_policy_file_set_mem; + policydb_create = sepol_policydb_create; + policydb_free = sepol_policydb_free; + policydb_read = sepol_policydb_read; + policydb_set_vers = sepol_policydb_set_vers; + policydb_to_image = sepol_policydb_to_image; + genbools_array = sepol_genbools_array; + genusers = sepol_genusers; + genbools = sepol_genbools; + +#endif + + /* + * Check whether we need to support local boolean and user definitions. + */ + if (setlocaldefs) { + if (access(selinux_booleans_path(), F_OK) == 0) + goto checkbool; + snprintf(path, sizeof path, "%s.local", selinux_booleans_path()); + if (access(path, F_OK) == 0) + goto checkbool; + snprintf(path, sizeof path, "%s/local.users", selinux_users_path()); + if (access(path, F_OK) == 0) + goto checkbool; + /* No local definition files, so disable setlocaldefs. */ + setlocaldefs = 0; + } + +checkbool: + /* + * As of Linux 2.6.22, the kernel preserves boolean + * values across a reload, so we do not need to + * preserve them in userspace. + */ + if (preservebools && uname(&uts) == 0 && strverscmp(uts.release, "2.6.22") >= 0) + preservebools = 0; + + if (usesepol) { + maxvers = vers_max(); + minvers = vers_min(); + if (!setlocaldefs && !preservebools) + maxvers = max(kernvers, maxvers); + } + + vers = maxvers; + search: + snprintf(path, sizeof(path), "%s.%d", + selinux_binary_policy_path(), vers); + fd = open(path, O_RDONLY); + while (fd < 0 && errno == ENOENT + && --vers >= minvers) { + /* Check prior versions to see if old policy is available */ + snprintf(path, sizeof(path), "%s.%d", + selinux_binary_policy_path(), vers); + fd = open(path, O_RDONLY); + } + if (fd < 0) { + fprintf(stderr, + "SELinux: Could not open policy file <= %s.%d: %s\n", + selinux_binary_policy_path(), maxvers, strerror(errno)); + goto dlclose; + } + + if (fstat(fd, &sb) < 0) { + fprintf(stderr, + "SELinux: Could not stat policy file %s: %s\n", + path, strerror(errno)); + goto close; + } + + prot = PROT_READ; + if (setlocaldefs || preservebools) + prot |= PROT_WRITE; + + size = sb.st_size; + data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, + "SELinux: Could not map policy file %s: %s\n", + path, strerror(errno)); + goto close; + } + + if (vers > kernvers && usesepol) { + /* Need to downgrade to kernel-supported version. */ + if (policy_file_create(&pf)) + goto unmap; + if (policydb_create(&policydb)) { + policy_file_free(pf); + goto unmap; + } + policy_file_set_mem(pf, data, size); + if (policydb_read(policydb, pf)) { + policy_file_free(pf); + policydb_free(policydb); + goto unmap; + } + if (policydb_set_vers(policydb, kernvers) || + policydb_to_image(NULL, policydb, &data, &size)) { + /* Downgrade failed, keep searching. */ + fprintf(stderr, + "SELinux: Could not downgrade policy file %s, searching for an older version.\n", + path); + policy_file_free(pf); + policydb_free(policydb); + munmap(map, sb.st_size); + close(fd); + vers--; + goto search; + } + policy_file_free(pf); + policydb_free(policydb); + } + + if (usesepol) { + if (setlocaldefs) { + void *olddata = data; + size_t oldsize = size; + rc = genusers(olddata, oldsize, selinux_users_path(), + &data, &size); + if (rc < 0) { + /* Fall back to the prior image if genusers failed. */ + data = olddata; + size = oldsize; + rc = 0; + } else { + if (olddata != map) + free(olddata); + } + } + +#ifndef DISABLE_BOOL + if (preservebools) { + int *values, len, i; + char **names; + rc = security_get_boolean_names(&names, &len); + if (!rc) { + values = malloc(sizeof(int) * len); + if (!values) + goto unmap; + for (i = 0; i < len; i++) + values[i] = + security_get_boolean_active(names[i]); + (void)genbools_array(data, size, names, values, + len); + free(values); + for (i = 0; i < len; i++) + free(names[i]); + free(names); + } + } else if (setlocaldefs) { + (void)genbools(data, size, + (char *)selinux_booleans_path()); + } +#endif + } + + + rc = security_load_policy(data, size); + + if (rc) + fprintf(stderr, + "SELinux: Could not load policy file %s: %s\n", + path, strerror(errno)); + + unmap: + if (data != map) + free(data); + munmap(map, sb.st_size); + close: + close(fd); + dlclose: +#ifdef SHARED + if (errormsg) + fprintf(stderr, "libselinux: %s\n", errormsg); + if (libsepolh) + dlclose(libsepolh); +#endif + return rc; +} + +hidden_def(selinux_mkload_policy) + +/* + * Mount point for selinuxfs. + * This definition is private to the function below. + * Everything else uses the location determined during + * libselinux startup via /proc/mounts (see init_selinuxmnt). + * We only need the hardcoded definition for the initial mount + * required for the initial policy load. + */ +int selinux_init_load_policy(int *enforce) +{ + int rc = 0, orig_enforce = 0, seconfig = -2, secmdline = -1; + FILE *cfg; + char *buf; + + /* + * Reread the selinux configuration in case it has changed. + * Example: Caller has chroot'd and is now loading policy from + * chroot'd environment. + */ + selinux_reset_config(); + + /* + * Get desired mode (disabled, permissive, enforcing) from + * /etc/selinux/config. + */ + selinux_getenforcemode(&seconfig); + + /* Check for an override of the mode via the kernel command line. */ + rc = mount("proc", "/proc", "proc", 0, 0); + cfg = fopen("/proc/cmdline", "r"); + if (cfg) { + char *tmp; + buf = malloc(selinux_page_size); + if (!buf) { + fclose(cfg); + return -1; + } + if (fgets(buf, selinux_page_size, cfg) && + (tmp = strstr(buf, "enforcing="))) { + if (tmp == buf || isspace(*(tmp - 1))) { + secmdline = + atoi(tmp + sizeof("enforcing=") - 1); + } + } + fclose(cfg); + free(buf); + } + + /* + * Determine the final desired mode. + * Command line argument takes precedence, then config file. + */ + if (secmdline >= 0) + *enforce = secmdline; + else if (seconfig >= 0) + *enforce = seconfig; + else + *enforce = 0; /* unspecified or disabled */ + + /* + * Check for the existence of SELinux via selinuxfs, and + * mount it if present for use in the calls below. + */ + const char *mntpoint = NULL; + /* First make sure /sys is mounted */ + if (mount("sysfs", "/sys", "sysfs", 0, 0) == 0 || errno == EBUSY) { + if (mount(SELINUXFS, SELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = SELINUXMNT; + } else { + /* check old mountpoint */ + if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = OLDSELINUXMNT; + } + } + } else { + /* check old mountpoint */ + if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = OLDSELINUXMNT; + } + } + + if (! mntpoint ) { + if (errno == ENODEV || !selinuxfs_exists()) { + /* + * SELinux was disabled in the kernel, either + * omitted entirely or disabled at boot via selinux=0. + * This takes precedence over any config or + * commandline enforcing setting. + */ + *enforce = 0; + } else { + /* Only emit this error if selinux was not disabled */ + fprintf(stderr, "Mount failed for selinuxfs on %s: %s\n", SELINUXMNT, strerror(errno)); + } + + if (rc == 0) + umount2("/proc", MNT_DETACH); + + goto noload; + } + set_selinuxmnt(mntpoint); + + if (rc == 0) + umount2("/proc", MNT_DETACH); + + /* + * Note: The following code depends on having selinuxfs + * already mounted and selinuxmnt set above. + */ + + if (seconfig == -1) { + /* Runtime disable of SELinux. */ + rc = security_disable(); + if (rc == 0) { + /* Successfully disabled, so umount selinuxfs too. */ + umount(selinux_mnt); + fini_selinuxmnt(); + goto noload; + } else { + /* + * It's possible that this failed because policy has + * already been loaded. We can't disable SELinux now, + * so the best we can do is force it to be permissive. + */ + *enforce = 0; + } + } + + /* + * If necessary, change the kernel enforcing status to match + * the desired mode. + */ + orig_enforce = rc = security_getenforce(); + if (rc < 0) + goto noload; + if (orig_enforce != *enforce) { + rc = security_setenforce(*enforce); + if (rc < 0) { + fprintf(stderr, "SELinux: Unable to switch to %s mode: %s\n", (*enforce ? "enforcing" : "permissive"), strerror(errno)); + if (*enforce) + goto noload; + } + } + + if (seconfig == -1) + goto noload; + + /* Load the policy. */ + return selinux_mkload_policy(0); + + noload: + /* + * Only return 0 on a successful completion of policy load. + * In any other case, we want to return an error so that init + * knows not to proceed with the re-exec for the domain transition. + * Depending on the *enforce setting, init will halt (> 0) or proceed + * normally (otherwise). + */ + return -1; +}
diff --git a/selinux/libselinux/src/lsetfilecon.c b/selinux/libselinux/src/lsetfilecon.c new file mode 100644 index 0000000..1d3b28a --- /dev/null +++ b/selinux/libselinux/src/lsetfilecon.c
@@ -0,0 +1,43 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "selinux_internal.h" +#include "policy.h" + +int lsetfilecon_raw(const char *path, const char * context) +{ + int rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, + 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((lgetfilecon_raw(path, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(lsetfilecon_raw) + +int lsetfilecon(const char *path, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = lsetfilecon_raw(path, rcontext); + + freecon(rcontext); + + return ret; +}
diff --git a/selinux/libselinux/src/mapping.c b/selinux/libselinux/src/mapping.c new file mode 100644 index 0000000..f205804 --- /dev/null +++ b/selinux/libselinux/src/mapping.c
@@ -0,0 +1,210 @@ +/* + * Class and permission mappings. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <selinux/selinux.h> +#include <selinux/avc.h> +#include "mapping.h" + +/* + * Class and permission mappings + */ + +struct selinux_mapping { + security_class_t value; /* real, kernel value */ + unsigned num_perms; + access_vector_t perms[sizeof(access_vector_t) * 8]; +}; + +static struct selinux_mapping *current_mapping = NULL; +static security_class_t current_mapping_size = 0; + +/* + * Mapping setting function + */ + +int +selinux_set_mapping(struct security_class_mapping *map) +{ + size_t size = sizeof(struct selinux_mapping); + security_class_t i, j; + unsigned k; + + free(current_mapping); + current_mapping = NULL; + current_mapping_size = 0; + + if (avc_reset() < 0) + goto err; + + /* Find number of classes in the input mapping */ + if (!map) { + errno = EINVAL; + goto err; + } + i = 0; + while (map[i].name) + i++; + + /* Allocate space for the class records, plus one for class zero */ + current_mapping = (struct selinux_mapping *)calloc(++i, size); + if (!current_mapping) + goto err; + + /* Store the raw class and permission values */ + j = 0; + while (map[j].name) { + struct security_class_mapping *p_in = map + (j++); + struct selinux_mapping *p_out = current_mapping + j; + + p_out->value = string_to_security_class(p_in->name); + if (!p_out->value) + goto err2; + + k = 0; + while (p_in->perms[k]) { + /* An empty permission string skips ahead */ + if (!*p_in->perms[k]) { + k++; + continue; + } + p_out->perms[k] = string_to_av_perm(p_out->value, + p_in->perms[k]); + if (!p_out->perms[k]) + goto err2; + k++; + } + p_out->num_perms = k; + } + + /* Set the mapping size here so the above lookups are "raw" */ + current_mapping_size = i; + return 0; +err2: + free(current_mapping); + current_mapping = NULL; + current_mapping_size = 0; +err: + return -1; +} + +/* + * Get real, kernel values from mapped values + */ + +security_class_t +unmap_class(security_class_t tclass) +{ + if (tclass < current_mapping_size) + return current_mapping[tclass].value; + + /* If here no mapping set or the class requested is not valid. */ + if (current_mapping_size != 0) { + errno = EINVAL; + return 0; + } + else + return tclass; +} + +access_vector_t +unmap_perm(security_class_t tclass, access_vector_t tperm) +{ + if (tclass < current_mapping_size) { + unsigned i; + access_vector_t kperm = 0; + + for (i=0; i<current_mapping[tclass].num_perms; i++) + if (tperm & (1<<i)) { + kperm |= current_mapping[tclass].perms[i]; + tperm &= ~(1<<i); + } + return kperm; + } + + /* If here no mapping set or the perm requested is not valid. */ + if (current_mapping_size != 0) { + errno = EINVAL; + return 0; + } + else + return tperm; +} + +/* + * Get mapped values from real, kernel values + */ + +security_class_t +map_class(security_class_t kclass) +{ + security_class_t i; + + for (i=0; i<current_mapping_size; i++) + if (current_mapping[i].value == kclass) + return i; + +/* If here no mapping set or the class requested is not valid. */ + if (current_mapping_size != 0) { + errno = EINVAL; + return 0; + } + else + return kclass; +} + +access_vector_t +map_perm(security_class_t tclass, access_vector_t kperm) +{ + if (tclass < current_mapping_size) { + unsigned i; + access_vector_t tperm = 0; + + for (i=0; i<current_mapping[tclass].num_perms; i++) + if (kperm & current_mapping[tclass].perms[i]) { + tperm |= 1<<i; + kperm &= ~current_mapping[tclass].perms[i]; + } + + if (tperm == 0) { + errno = EINVAL; + return 0; + } + else + return tperm; + } + return kperm; +} + +void +map_decision(security_class_t tclass, struct av_decision *avd) +{ + if (tclass < current_mapping_size) { + unsigned i; + access_vector_t result; + + for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) + if (avd->allowed & current_mapping[tclass].perms[i]) + result |= 1<<i; + avd->allowed = result; + + for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) + if (avd->decided & current_mapping[tclass].perms[i]) + result |= 1<<i; + avd->decided = result; + + for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) + if (avd->auditallow & current_mapping[tclass].perms[i]) + result |= 1<<i; + avd->auditallow = result; + + for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) + if (avd->auditdeny & current_mapping[tclass].perms[i]) + result |= 1<<i; + avd->auditdeny = result; + } +}
diff --git a/selinux/libselinux/src/mapping.h b/selinux/libselinux/src/mapping.h new file mode 100644 index 0000000..b96756b --- /dev/null +++ b/selinux/libselinux/src/mapping.h
@@ -0,0 +1,41 @@ +/* + * This file describes the class and permission mappings used to + * hide the kernel numbers from userspace by allowing userspace object + * managers to specify a list of classes and permissions. + */ +#ifndef _SELINUX_MAPPING_H_ +#define _SELINUX_MAPPING_H_ + +#include <selinux/selinux.h> + +/* + * Get real, kernel values from mapped values + */ + +extern security_class_t +unmap_class(security_class_t tclass); + +extern access_vector_t +unmap_perm(security_class_t tclass, access_vector_t tperm); + +/* + * Get mapped values from real, kernel values + */ + +extern security_class_t +map_class(security_class_t kclass); + +extern access_vector_t +map_perm(security_class_t tclass, access_vector_t kperm); + +extern void +map_decision(security_class_t tclass, struct av_decision *avd); + +/*mapping is not used for embedded build*/ +#ifdef DISABLE_AVC +#define unmap_perm(x,y) y +#define unmap_class(x) x +#define map_decision(x,y) +#endif + +#endif /* _SELINUX_MAPPING_H_ */
diff --git a/selinux/libselinux/src/matchmediacon.c b/selinux/libselinux/src/matchmediacon.c new file mode 100644 index 0000000..46cba46 --- /dev/null +++ b/selinux/libselinux/src/matchmediacon.c
@@ -0,0 +1,67 @@ +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <string.h> +#include "selinux_internal.h" +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <regex.h> +#include <stdarg.h> + +int matchmediacon(const char *media, char ** con) +{ + const char *path = selinux_media_context_path(); + FILE *infile; + char *ptr, *ptr2 = NULL; + int found = 0; + char current_line[PATH_MAX]; + if ((infile = fopen(path, "r")) == NULL) + return -1; + while (!feof_unlocked(infile)) { + if (!fgets_unlocked(current_line, sizeof(current_line), infile)) { + return -1; + } + if (current_line[strlen(current_line) - 1]) + current_line[strlen(current_line) - 1] = 0; + /* Skip leading whitespace before the partial context. */ + ptr = current_line; + while (*ptr && isspace(*ptr)) + ptr++; + + if (!(*ptr)) + continue; + + /* Find the end of the media context. */ + ptr2 = ptr; + while (*ptr2 && !isspace(*ptr2)) + ptr2++; + if (!(*ptr2)) + continue; + + *ptr2++ = 0; + if (strcmp(media, ptr) == 0) { + found = 1; + break; + } + } + fclose(infile); + if (!found) + return -1; + + /* Skip whitespace. */ + while (*ptr2 && isspace(*ptr2)) + ptr2++; + if (!(*ptr2)) { + return -1; + } + + if (selinux_raw_to_trans_context(ptr2, con)) { + *con = NULL; + return -1; + } + + return 0; +}
diff --git a/selinux/libselinux/src/matchpathcon.c b/selinux/libselinux/src/matchpathcon.c new file mode 100644 index 0000000..5b495a0 --- /dev/null +++ b/selinux/libselinux/src/matchpathcon.c
@@ -0,0 +1,554 @@ +#include <sys/stat.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include "selinux_internal.h" +#include "label_internal.h" +#include "callbacks.h" +#include <limits.h> + +static __thread struct selabel_handle *hnd; + +/* + * An array for mapping integers to contexts + */ +static __thread char **con_array; +static __thread int con_array_size; +static __thread int con_array_used; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; + +static int add_array_elt(char *con) +{ + if (con_array_size) { + while (con_array_used >= con_array_size) { + con_array_size *= 2; + con_array = (char **)realloc(con_array, sizeof(char*) * + con_array_size); + if (!con_array) { + con_array_size = con_array_used = 0; + return -1; + } + } + } else { + con_array_size = 1000; + con_array = (char **)malloc(sizeof(char*) * con_array_size); + if (!con_array) { + con_array_size = con_array_used = 0; + return -1; + } + } + + con_array[con_array_used] = strdup(con); + if (!con_array[con_array_used]) + return -1; + return con_array_used++; +} + +static void free_array_elts(void) +{ + con_array_size = con_array_used = 0; + free(con_array); + con_array = NULL; +} + +static void +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))) +#endif + default_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))) +#endif + (*myprintf) (const char *fmt,...) = &default_printf; +int myprintf_compat = 0; + +void set_matchpathcon_printf(void (*f) (const char *fmt, ...)) +{ + myprintf = f ? f : &default_printf; + myprintf_compat = 1; +} + +static int (*myinvalidcon) (const char *p, unsigned l, char *c) = NULL; + +void set_matchpathcon_invalidcon(int (*f) (const char *p, unsigned l, char *c)) +{ + myinvalidcon = f; +} + +static int default_canoncon(const char *path, unsigned lineno, char **context) +{ + char *tmpcon; + if (security_canonicalize_context_raw(*context, &tmpcon) < 0) { + if (errno == ENOENT) + return 0; + if (lineno) + myprintf("%s: line %u has invalid context %s\n", path, + lineno, *context); + else + myprintf("%s: invalid context %s\n", path, *context); + return 1; + } + free(*context); + *context = tmpcon; + return 0; +} + +static int (*mycanoncon) (const char *p, unsigned l, char **c) = + NULL; + +void set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c)) +{ + if (f) + mycanoncon = f; + else + mycanoncon = &default_canoncon; +} + +static __thread struct selinux_opt options[SELABEL_NOPT]; +static __thread int notrans; + +void set_matchpathcon_flags(unsigned int flags) +{ + int i; + memset(options, 0, sizeof(options)); + i = SELABEL_OPT_BASEONLY; + options[i].type = i; + options[i].value = (flags & MATCHPATHCON_BASEONLY) ? (char*)1 : NULL; + i = SELABEL_OPT_VALIDATE; + options[i].type = i; + options[i].value = (flags & MATCHPATHCON_VALIDATE) ? (char*)1 : NULL; + notrans = flags & MATCHPATHCON_NOTRANS; +} + +/* + * An association between an inode and a + * specification. + */ +typedef struct file_spec { + ino_t ino; /* inode number */ + int specind; /* index of specification in spec */ + char *file; /* full pathname for diagnostic messages about conflicts */ + struct file_spec *next; /* next association in hash bucket chain */ +} file_spec_t; + +/* + * The hash table of associations, hashed by inode number. + * Chaining is used for collisions, with elements ordered + * by inode number in each bucket. Each hash bucket has a dummy + * header. + */ +#define HASH_BITS 16 +#define HASH_BUCKETS (1 << HASH_BITS) +#define HASH_MASK (HASH_BUCKETS-1) +static file_spec_t *fl_head; + +/* + * Try to add an association between an inode and + * a specification. If there is already an association + * for the inode and it conflicts with this specification, + * then use the specification that occurs later in the + * specification array. + */ +int matchpathcon_filespec_add(ino_t ino, int specind, const char *file) +{ + file_spec_t *prevfl, *fl; + int h, ret; + struct stat sb; + + if (!fl_head) { + fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + if (!fl_head) + goto oom; + memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); + } + + h = (ino + (ino >> HASH_BITS)) & HASH_MASK; + for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; + prevfl = fl, fl = fl->next) { + if (ino == fl->ino) { + ret = lstat(fl->file, &sb); + if (ret < 0 || sb.st_ino != ino) { + fl->specind = specind; + free(fl->file); + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom; + strcpy(fl->file, file); + return fl->specind; + + } + + if (!strcmp(con_array[fl->specind], + con_array[specind])) + return fl->specind; + + myprintf + ("%s: conflicting specifications for %s and %s, using %s.\n", + __FUNCTION__, file, fl->file, + con_array[fl->specind]); + free(fl->file); + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom; + strcpy(fl->file, file); + return fl->specind; + } + + if (ino > fl->ino) + break; + } + + fl = malloc(sizeof(file_spec_t)); + if (!fl) + goto oom; + fl->ino = ino; + fl->specind = specind; + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom_freefl; + strcpy(fl->file, file); + fl->next = prevfl->next; + prevfl->next = fl; + return fl->specind; + oom_freefl: + free(fl); + oom: + myprintf("%s: insufficient memory for file label entry for %s\n", + __FUNCTION__, file); + return -1; +} + +/* + * Evaluate the association hash table distribution. + */ +void matchpathcon_filespec_eval(void) +{ + file_spec_t *fl; + int h, used, nel, len, longest; + + if (!fl_head) + return; + + used = 0; + longest = 0; + nel = 0; + for (h = 0; h < HASH_BUCKETS; h++) { + len = 0; + for (fl = fl_head[h].next; fl; fl = fl->next) { + len++; + } + if (len) + used++; + if (len > longest) + longest = len; + nel += len; + } + + myprintf + ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", + __FUNCTION__, nel, used, HASH_BUCKETS, longest); +} + +/* + * Destroy the association hash table. + */ +void matchpathcon_filespec_destroy(void) +{ + file_spec_t *fl, *tmp; + int h; + + free_array_elts(); + + if (!fl_head) + return; + + for (h = 0; h < HASH_BUCKETS; h++) { + fl = fl_head[h].next; + while (fl) { + tmp = fl; + fl = fl->next; + free(tmp->file); + free(tmp); + } + fl_head[h].next = NULL; + } + free(fl_head); + fl_head = NULL; +} + +static void matchpathcon_thread_destructor(void __attribute__((unused)) *ptr) +{ + matchpathcon_fini(); +} + +void __attribute__((destructor)) matchpathcon_lib_destructor(void); + +void hidden __attribute__((destructor)) matchpathcon_lib_destructor(void) +{ + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static void matchpathcon_init_once(void) +{ + if (__selinux_key_create(&destructor_key, matchpathcon_thread_destructor) == 0) + destructor_key_initialized = 1; +} + +int matchpathcon_init_prefix(const char *path, const char *subset) +{ + if (!mycanoncon) + mycanoncon = default_canoncon; + + __selinux_once(once, matchpathcon_init_once); + __selinux_setspecific(destructor_key, (void *)1); + + options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; + options[SELABEL_OPT_SUBSET].value = subset; + options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH; + options[SELABEL_OPT_PATH].value = path; + + hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT); + return hnd ? 0 : -1; +} + +hidden_def(matchpathcon_init_prefix) + +int matchpathcon_init(const char *path) +{ + return matchpathcon_init_prefix(path, NULL); +} + +void matchpathcon_fini(void) +{ + free_array_elts(); + + if (hnd) { + selabel_close(hnd); + hnd = NULL; + } +} + +/* + * We do not want to resolve a symlink to a real path if it is the final + * component of the name. Thus we split the pathname on the last "/" and + * determine a real path component of the first portion. We then have to + * copy the last part back on to get the final real path. Wheww. + */ +int realpath_not_final(const char *name, char *resolved_path) +{ + char *last_component; + char *tmp_path, *p; + size_t len = 0; + int rc = 0; + + tmp_path = strdup(name); + if (!tmp_path) { + myprintf("symlink_realpath(%s) strdup() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + /* strip leading // */ + while (tmp_path[len] && tmp_path[len] == '/' && + tmp_path[len+1] && tmp_path[len+1] == '/') { + tmp_path++; + len++; + } + last_component = strrchr(tmp_path, '/'); + + if (last_component == tmp_path) { + last_component++; + p = strcpy(resolved_path, ""); + } else if (last_component) { + *last_component = '\0'; + last_component++; + p = realpath(tmp_path, resolved_path); + } else { + last_component = tmp_path; + p = realpath("./", resolved_path); + } + + if (!p) { + myprintf("symlink_realpath(%s) realpath() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + len = strlen(p); + if (len + strlen(last_component) + 2 > PATH_MAX) { + myprintf("symlink_realpath(%s) failed: Filename too long \n", + name); + errno=ENAMETOOLONG; + rc = -1; + goto out; + } + + resolved_path += len; + strcpy(resolved_path, "/"); + resolved_path += 1; + strcpy(resolved_path, last_component); +out: + free(tmp_path); + return rc; +} + +int matchpathcon(const char *path, mode_t mode, char ** con) +{ + char stackpath[PATH_MAX + 1]; + char *p = NULL; + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + if (S_ISLNK(mode)) { + if (!realpath_not_final(path, stackpath)) + path = stackpath; + } else { + p = realpath(path, stackpath); + if (p) + path = p; + } + + return notrans ? + selabel_lookup_raw(hnd, con, path, mode) : + selabel_lookup(hnd, con, path, mode); +} + +int matchpathcon_index(const char *name, mode_t mode, char ** con) +{ + int i = matchpathcon(name, mode, con); + + if (i < 0) + return -1; + + return add_array_elt(*con); +} + +void matchpathcon_checkmatches(char *str __attribute__((unused))) +{ + selabel_stats(hnd); +} + +/* Compare two contexts to see if their differences are "significant", + * or whether the only difference is in the user. */ +int selinux_file_context_cmp(const char * a, + const char * b) +{ + char *rest_a, *rest_b; /* Rest of the context after the user */ + if (!a && !b) + return 0; + if (!a) + return -1; + if (!b) + return 1; + rest_a = strchr((char *)a, ':'); + rest_b = strchr((char *)b, ':'); + if (!rest_a && !rest_b) + return 0; + if (!rest_a) + return -1; + if (!rest_b) + return 1; + return strcmp(rest_a, rest_b); +} + +int selinux_file_context_verify(const char *path, mode_t mode) +{ + char * con = NULL; + char * fcontext = NULL; + int rc = 0; + + rc = lgetfilecon_raw(path, &con); + if (rc == -1) { + if (errno != ENOTSUP) + return -1; + else + return 0; + } + + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) { + if (errno != ENOENT) + rc = -1; + else + rc = 0; + } else { + /* + * Need to set errno to 0 as it can be set to ENOENT if the + * file_contexts.subs file does not exist (see selabel_open in + * label.c), thus causing confusion if errno is checked on return. + */ + errno = 0; + rc = (selinux_file_context_cmp(fcontext, con) == 0); + } + + freecon(con); + freecon(fcontext); + return rc; +} + +int selinux_lsetfilecon_default(const char *path) +{ + struct stat st; + int rc = -1; + char * scontext = NULL; + if (lstat(path, &st) != 0) + return rc; + + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + /* If there's an error determining the context, or it has none, + return to allow default context */ + if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) { + if (errno == ENOENT) + rc = 0; + } else { + rc = lsetfilecon_raw(path, scontext); + freecon(scontext); + } + return rc; +} + +int compat_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts, + const char *path, unsigned lineno) +{ + int rc; + char **ctx = &contexts->ctx_raw; + + if (myinvalidcon) + rc = myinvalidcon(path, lineno, *ctx); + else if (mycanoncon) + rc = mycanoncon(path, lineno, ctx); + else { + rc = selabel_validate(rec, contexts); + if (rc < 0) { + if (lineno) { + COMPAT_LOG(SELINUX_WARNING, + "%s: line %u has invalid context %s\n", + path, lineno, *ctx); + } else { + COMPAT_LOG(SELINUX_WARNING, + "%s: has invalid context %s\n", path, *ctx); + } + } + } + + return rc ? -1 : 0; +}
diff --git a/selinux/libselinux/src/policy.h b/selinux/libselinux/src/policy.h new file mode 100644 index 0000000..bf270b5 --- /dev/null +++ b/selinux/libselinux/src/policy.h
@@ -0,0 +1,29 @@ +#ifndef _POLICY_H_ +#define _POLICY_H_ + +/* Private definitions used internally by libselinux. */ + +/* xattr name for SELinux attributes. */ +#define XATTR_NAME_SELINUX "security.selinux" + +/* Initial length guess for getting contexts. */ +#define INITCONTEXTLEN 255 + +/* selinux file system type */ +#define SELINUXFS "selinuxfs" + +/* selinuxfs magic number */ +#define SELINUX_MAGIC 0xf97cff8c + +/* Preferred selinux mount location */ +#define SELINUXMNT "/sys/fs/selinux" +#define OLDSELINUXMNT "/selinux" + +/* selinuxfs mount point */ +extern char *selinux_mnt; + +#define FILECONTEXTS "/etc/security/selinux/file_contexts" + +#define DEFAULT_POLICY_VERSION 15 + +#endif
diff --git a/selinux/libselinux/src/policyvers.c b/selinux/libselinux/src/policyvers.c new file mode 100644 index 0000000..284a7f7 --- /dev/null +++ b/selinux/libselinux/src/policyvers.c
@@ -0,0 +1,45 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include <stdio.h> +#include "policy.h" +#include "dso.h" +#include <limits.h> + +int security_policyvers(void) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + unsigned vers = DEFAULT_POLICY_VERSION; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/policyvers", selinux_mnt); + fd = open(path, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return vers; + else + return -1; + } + memset(buf, 0, sizeof buf); + ret = read(fd, buf, sizeof buf - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%u", &vers) != 1) + return -1; + + return vers; +} + +hidden_def(security_policyvers)
diff --git a/selinux/libselinux/src/procattr.c b/selinux/libselinux/src/procattr.c new file mode 100644 index 0000000..eee4612 --- /dev/null +++ b/selinux/libselinux/src/procattr.c
@@ -0,0 +1,352 @@ +#include <sys/syscall.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include "selinux_internal.h" +#include "policy.h" + +#define UNSET (char *) -1 + +static __thread char *prev_current = UNSET; +static __thread char * prev_exec = UNSET; +static __thread char * prev_fscreate = UNSET; +static __thread char * prev_keycreate = UNSET; +static __thread char * prev_sockcreate = UNSET; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; +static __thread char destructor_initialized; + +static pid_t gettid(void) +{ + return syscall(__NR_gettid); +} + +static void procattr_thread_destructor(void __attribute__((unused)) *unused) +{ + if (prev_current != UNSET) + free(prev_current); + if (prev_exec != UNSET) + free(prev_exec); + if (prev_fscreate != UNSET) + free(prev_fscreate); + if (prev_keycreate != UNSET) + free(prev_keycreate); + if (prev_sockcreate != UNSET) + free(prev_sockcreate); +} + +void __attribute__((destructor)) procattr_destructor(void); + +void hidden __attribute__((destructor)) procattr_destructor(void) +{ + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static inline void init_thread_destructor(void) +{ + if (destructor_initialized == 0) { + __selinux_setspecific(destructor_key, (void *)1); + destructor_initialized = 1; + } +} + +static void init_procattr(void) +{ + if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) { + destructor_key_initialized = 1; + } +} + +static int openattr(pid_t pid, const char *attr, int flags) +{ + int fd, rc; + char *path; + pid_t tid; + + if (pid > 0) { + rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); + } else if (pid == 0) { + rc = asprintf(&path, "/proc/thread-self/attr/%s", attr); + if (rc < 0) + return -1; + fd = open(path, flags | O_CLOEXEC); + if (fd >= 0 || errno != ENOENT) + goto out; + free(path); + tid = gettid(); + rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); + } else { + errno = EINVAL; + return -1; + } + if (rc < 0) + return -1; + + fd = open(path, flags | O_CLOEXEC); +out: + free(path); + return fd; +} + +static int getprocattrcon_raw(char ** context, + pid_t pid, const char *attr) +{ + char *buf; + size_t size; + int fd; + ssize_t ret; + int errno_hold; + char * prev_context; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + + switch (attr[0]) { + case 'c': + prev_context = prev_current; + break; + case 'e': + prev_context = prev_exec; + break; + case 'f': + prev_context = prev_fscreate; + break; + case 'k': + prev_context = prev_keycreate; + break; + case 's': + prev_context = prev_sockcreate; + break; + case 'p': + prev_context = NULL; + break; + default: + errno = ENOENT; + return -1; + }; + + if (prev_context && prev_context != UNSET) { + *context = strdup(prev_context); + if (!(*context)) { + return -1; + } + return 0; + } + + fd = openattr(pid, attr, O_RDONLY); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + memset(buf, 0, size); + + do { + ret = read(fd, buf, size - 1); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + goto out2; + + if (ret == 0) { + *context = NULL; + goto out2; + } + + *context = strdup(buf); + if (!(*context)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + errno_hold = errno; + close(fd); + errno = errno_hold; + return ret; +} + +static int getprocattrcon(char ** context, + pid_t pid, const char *attr) +{ + int ret; + char * rcontext; + + ret = getprocattrcon_raw(&rcontext, pid, attr); + + if (!ret) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + return ret; +} + +static int setprocattrcon_raw(const char * context, + pid_t pid, const char *attr) +{ + int fd; + ssize_t ret; + int errno_hold; + char **prev_context, *context2 = NULL; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + + switch (attr[0]) { + case 'c': + prev_context = &prev_current; + break; + case 'e': + prev_context = &prev_exec; + break; + case 'f': + prev_context = &prev_fscreate; + break; + case 'k': + prev_context = &prev_keycreate; + break; + case 's': + prev_context = &prev_sockcreate; + break; + default: + errno = ENOENT; + return -1; + }; + + if (!context && !*prev_context) + return 0; + if (context && *prev_context && *prev_context != UNSET + && !strcmp(context, *prev_context)) + return 0; + + fd = openattr(pid, attr, O_RDWR); + if (fd < 0) + return -1; + if (context) { + ret = -1; + context2 = strdup(context); + if (!context2) + goto out; + do { + ret = write(fd, context2, strlen(context2) + 1); + } while (ret < 0 && errno == EINTR); + } else { + do { + ret = write(fd, NULL, 0); /* clear */ + } while (ret < 0 && errno == EINTR); + } +out: + errno_hold = errno; + close(fd); + errno = errno_hold; + if (ret < 0) { + free(context2); + return -1; + } else { + if (*prev_context != UNSET) + free(*prev_context); + *prev_context = context2; + return 0; + } +} + +static int setprocattrcon(const char * context, + pid_t pid, const char *attr) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = setprocattrcon_raw(rcontext, pid, attr); + + freecon(rcontext); + + return ret; +} + +#define getselfattr_def(fn, attr) \ + int get##fn##_raw(char **c) \ + { \ + return getprocattrcon_raw(c, 0, #attr); \ + } \ + int get##fn(char **c) \ + { \ + return getprocattrcon(c, 0, #attr); \ + } + +#define setselfattr_def(fn, attr) \ + int set##fn##_raw(const char * c) \ + { \ + return setprocattrcon_raw(c, 0, #attr); \ + } \ + int set##fn(const char * c) \ + { \ + return setprocattrcon(c, 0, #attr); \ + } + +#define all_selfattr_def(fn, attr) \ + getselfattr_def(fn, attr) \ + setselfattr_def(fn, attr) + +#define getpidattr_def(fn, attr) \ + int get##fn##_raw(pid_t pid, char **c) \ + { \ + if (pid <= 0) { \ + errno = EINVAL; \ + return -1; \ + } else { \ + return getprocattrcon_raw(c, pid, #attr); \ + } \ + } \ + int get##fn(pid_t pid, char **c) \ + { \ + if (pid <= 0) { \ + errno = EINVAL; \ + return -1; \ + } else { \ + return getprocattrcon(c, pid, #attr); \ + } \ + } + +all_selfattr_def(con, current) + getpidattr_def(pidcon, current) + getselfattr_def(prevcon, prev) + all_selfattr_def(execcon, exec) + all_selfattr_def(fscreatecon, fscreate) + all_selfattr_def(sockcreatecon, sockcreate) + all_selfattr_def(keycreatecon, keycreate) + + hidden_def(getcon_raw) + hidden_def(getcon) + hidden_def(getexeccon_raw) + hidden_def(getfilecon_raw) + hidden_def(getfilecon) + hidden_def(getfscreatecon_raw) + hidden_def(getkeycreatecon_raw) + hidden_def(getpeercon_raw) + hidden_def(getpidcon_raw) + hidden_def(getprevcon_raw) + hidden_def(getprevcon) + hidden_def(getsockcreatecon_raw) + hidden_def(setcon_raw) + hidden_def(setexeccon_raw) + hidden_def(setexeccon) + hidden_def(setfilecon_raw) + hidden_def(setfscreatecon_raw) + hidden_def(setkeycreatecon_raw) + hidden_def(setsockcreatecon_raw)
diff --git a/selinux/libselinux/src/query_user_context.c b/selinux/libselinux/src/query_user_context.c new file mode 100644 index 0000000..b8125c9 --- /dev/null +++ b/selinux/libselinux/src/query_user_context.c
@@ -0,0 +1,180 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "selinux_internal.h" +#include "context_internal.h" +#include <selinux/get_context_list.h> + +/* context_menu - given a list of contexts, presents a menu of security contexts + * to the user. Returns the number (position in the list) of + * the user selected context. + */ +static int context_menu(char ** list) +{ + int i; /* array index */ + int choice = 0; /* index of the user's choice */ + char response[10]; /* string to hold the user's response */ + + printf("\n\n"); + for (i = 0; list[i]; i++) + printf("[%d] %s\n", i + 1, list[i]); + + while ((choice < 1) || (choice > i)) { + printf("Enter number of choice: "); + fflush(stdin); + if (fgets(response, sizeof(response), stdin) == NULL) + continue; + fflush(stdin); + choice = strtol(response, NULL, 10); + } + + return (choice - 1); +} + +/* query_user_context - given a list of context, allow the user to choose one. The + * default is the first context in the list. Returns 0 on + * success, -1 on failure + */ +int query_user_context(char ** list, char ** usercon) +{ + char response[10]; /* The user's response */ + int choice; /* The index in the list of the sid chosen by + the user */ + + if (!list[0]) + return -1; + + printf("\nYour default context is %s.\n", list[0]); + if (list[1]) { + printf("Do you want to choose a different one? [n]"); + fflush(stdin); + if (fgets(response, sizeof(response), stdin) == NULL) + return -1; + fflush(stdin); + + if ((response[0] == 'y') || (response[0] == 'Y')) { + choice = context_menu(list); + *usercon = strdup(list[choice]); + if (!(*usercon)) + return -1; + return 0; + } + + *usercon = strdup(list[0]); + if (!(*usercon)) + return -1; + } else { + *usercon = strdup(list[0]); + if (!(*usercon)) + return -1; + } + + return 0; +} + +/* get_field - given fieldstr - the "name" of a field, query the user + * and set the new value of the field + */ +static void get_field(const char *fieldstr, char *newfield, int newfieldlen) +{ + int done = 0; /* true if a non-empty field has been obtained */ + + while (!done) { /* Keep going until we get a value for the field */ + printf("\tEnter %s ", fieldstr); + fflush(stdin); + if (fgets(newfield, newfieldlen, stdin) == NULL) + continue; + fflush(stdin); + if (newfield[strlen(newfield) - 1] == '\n') + newfield[strlen(newfield) - 1] = '\0'; + + if (strlen(newfield) == 0) { + printf("You must enter a %s\n", fieldstr); + } else { + done = 1; + } + } +} + +/* manual_user_enter_context - provides a way for a user to manually enter a + * context in case the policy doesn't allow a list + * to be obtained. + * given the userid, queries the user and places the + * context chosen by the user into usercon. Returns 0 + * on success. + */ +int manual_user_enter_context(const char *user, char ** newcon) +{ + char response[10]; /* Used to get yes or no answers from user */ + char role[100]; /* The role requested by the user */ + int rolelen = 100; + char type[100]; /* The type requested by the user */ + int typelen = 100; + char level[100]; /* The level requested by the user */ + int levellen = 100; + int mls_enabled = is_selinux_mls_enabled(); + + context_t new_context; /* The new context chosen by the user */ + char *user_context = NULL; /* String value of the user's context */ + int done = 0; /* true if a valid sid has been obtained */ + + /* Initialize the context. How this is done depends on whether + or not MLS is enabled */ + if (mls_enabled) + new_context = context_new("user:role:type:level"); + else + new_context = context_new("user:role:type"); + + if (!new_context) + return -1; + + while (!done) { + printf("Would you like to enter a security context? [y]"); + if (fgets(response, sizeof(response), stdin) == NULL + || (response[0] == 'n') || (response[0] == 'N')) { + context_free(new_context); + return -1; + } + + /* Allow the user to enter each field of the context individually */ + if (context_user_set(new_context, user)) { + context_free(new_context); + return -1; + } + get_field("role", role, rolelen); + if (context_role_set(new_context, role)) { + context_free(new_context); + return -1; + } + get_field("type", type, typelen); + if (context_type_set(new_context, type)) { + context_free(new_context); + return -1; + } + + if (mls_enabled) { + get_field("level", level, levellen); + if (context_range_set(new_context, level)) { + context_free(new_context); + return -1; + } + } + + /* Get the string value of the context and see if it is valid. */ + user_context = context_str(new_context); + if (!user_context) { + context_free(new_context); + return -1; + } + if (!security_check_context(user_context)) + done = 1; + else + printf("Not a valid security context\n"); + } + + *newcon = strdup(user_context); + context_free(new_context); + if (!(*newcon)) + return -1; + return 0; +}
diff --git a/selinux/libselinux/src/selinux_check_securetty_context.c b/selinux/libselinux/src/selinux_check_securetty_context.c new file mode 100644 index 0000000..24e5e2c --- /dev/null +++ b/selinux/libselinux/src/selinux_check_securetty_context.c
@@ -0,0 +1,53 @@ +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include "selinux_internal.h" +#include "context_internal.h" + +int selinux_check_securetty_context(const char * tty_context) +{ + char *line = NULL; + char *start, *end = NULL; + size_t line_len = 0; + ssize_t len; + int found = -1; + FILE *fp; + fp = fopen(selinux_securetty_types_path(), "r"); + if (fp) { + context_t con = context_new(tty_context); + if (con) { + const char *type = context_type_get(con); + while ((len = getline(&line, &line_len, fp)) != -1) { + + if (line[len - 1] == '\n') + line[len - 1] = 0; + + /* Skip leading whitespace. */ + start = line; + while (*start && isspace(*start)) + start++; + if (!(*start)) + continue; + + end = start; + while (*end && !isspace(*end)) + end++; + if (*end) + *end++ = 0; + if (!strcmp(type, start)) { + found = 0; + break; + } + } + free(line); + context_free(con); + } + fclose(fp); + } + + return found; +} + +hidden_def(selinux_check_securetty_context)
diff --git a/selinux/libselinux/src/selinux_config.c b/selinux/libselinux/src/selinux_config.c new file mode 100644 index 0000000..bec5f3b --- /dev/null +++ b/selinux/libselinux/src/selinux_config.c
@@ -0,0 +1,532 @@ +#include <stdio.h> +#include <stdio_ext.h> +#include <string.h> +#include <ctype.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <limits.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include "policy.h" +#include "selinux_internal.h" +#include "get_default_type_internal.h" + +#define SELINUXDEFAULT "targeted" +#define SELINUXTYPETAG "SELINUXTYPE=" +#define SELINUXTAG "SELINUX=" +#define SETLOCALDEFS "SETLOCALDEFS=" +#define REQUIRESEUSERS "REQUIRESEUSERS=" + +/* Indices for file paths arrays. */ +#define BINPOLICY 0 +#define CONTEXTS_DIR 1 +#define FILE_CONTEXTS 2 +#define HOMEDIR_CONTEXTS 3 +#define DEFAULT_CONTEXTS 4 +#define USER_CONTEXTS 5 +#define FAILSAFE_CONTEXT 6 +#define DEFAULT_TYPE 7 +#define BOOLEANS 8 +#define MEDIA_CONTEXTS 9 +#define REMOVABLE_CONTEXT 10 +#define CUSTOMIZABLE_TYPES 11 +#define USERS_DIR 12 +#define SEUSERS 13 +#define TRANSLATIONS 14 +#define NETFILTER_CONTEXTS 15 +#define FILE_CONTEXTS_HOMEDIR 16 +#define FILE_CONTEXTS_LOCAL 17 +#define SECURETTY_TYPES 18 +#define X_CONTEXTS 19 +#define COLORS 20 +#define VIRTUAL_DOMAIN 21 +#define VIRTUAL_IMAGE 22 +#define FILE_CONTEXT_SUBS 23 +#define SEPGSQL_CONTEXTS 24 +#define FILE_CONTEXT_SUBS_DIST 25 +#define LXC_CONTEXTS 26 +#define BOOLEAN_SUBS 27 +#define OPENSSH_CONTEXTS 28 +#define SYSTEMD_CONTEXTS 29 +#define NEL 30 + +/* Part of one-time lazy init */ +static pthread_once_t once = PTHREAD_ONCE_INIT; +static void init_selinux_config(void); + +/* New layout is relative to SELINUXDIR/policytype. */ +static char *file_paths[NEL]; +#define L1(l) L2(l) +#define L2(l)str##l +static const union file_path_suffixes_data { + struct { +#define S_(n, s) char L1(__LINE__)[sizeof(s)]; +#include "file_path_suffixes.h" +#undef S_ + }; + char str[0]; +} file_path_suffixes_data = { + { +#define S_(n, s) s, +#include "file_path_suffixes.h" +#undef S_ + } +}; +static const uint16_t file_path_suffixes_idx[NEL] = { +#define S_(n, s) [n] = offsetof(union file_path_suffixes_data, L1(__LINE__)), +#include "file_path_suffixes.h" +#undef S_ +}; + +#undef L1 +#undef L2 + +int selinux_getenforcemode(int *enforce) +{ + int ret = -1; + FILE *cfg = fopen(SELINUXCONFIG, "r"); + if (cfg) { + char *buf; + int len = sizeof(SELINUXTAG) - 1; + buf = malloc(selinux_page_size); + if (!buf) { + fclose(cfg); + return -1; + } + while (fgets_unlocked(buf, selinux_page_size, cfg)) { + if (strncmp(buf, SELINUXTAG, len)) + continue; + if (!strncasecmp + (buf + len, "enforcing", sizeof("enforcing") - 1)) { + *enforce = 1; + ret = 0; + break; + } else + if (!strncasecmp + (buf + len, "permissive", + sizeof("permissive") - 1)) { + *enforce = 0; + ret = 0; + break; + } else + if (!strncasecmp + (buf + len, "disabled", + sizeof("disabled") - 1)) { + *enforce = -1; + ret = 0; + break; + } + } + fclose(cfg); + free(buf); + } + return ret; +} + +hidden_def(selinux_getenforcemode) + +static char *selinux_policytype; + +int selinux_getpolicytype(char **type) +{ + __selinux_once(once, init_selinux_config); + if (!selinux_policytype) + return -1; + *type = strdup(selinux_policytype); + return *type ? 0 : -1; +} + +hidden_def(selinux_getpolicytype) + +static int setpolicytype(const char *type) +{ + free(selinux_policytype); + selinux_policytype = strdup(type); + return selinux_policytype ? 0 : -1; +} + +static char *selinux_policyroot = NULL; +static const char *selinux_rootpath = SELINUXDIR; + +static void init_selinux_config(void) +{ + int i, *intptr; + size_t line_len; + ssize_t len; + char *line_buf = NULL, *buf_p, *value, *type = NULL, *end; + FILE *fp; + + if (selinux_policyroot) + return; + + fp = fopen(SELINUXCONFIG, "r"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while ((len = getline(&line_buf, &line_len, fp)) > 0) { + if (line_buf[len - 1] == '\n') + line_buf[len - 1] = 0; + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + if (*buf_p == '#' || *buf_p == 0) + continue; + + if (!strncasecmp(buf_p, SELINUXTYPETAG, + sizeof(SELINUXTYPETAG) - 1)) { + selinux_policytype = type = + strdup(buf_p + sizeof(SELINUXTYPETAG) - 1); + if (!type) + return; + end = type + strlen(type) - 1; + while ((end > type) && + (isspace(*end) || iscntrl(*end))) { + *end = 0; + end--; + } + continue; + } else if (!strncmp(buf_p, SETLOCALDEFS, + sizeof(SETLOCALDEFS) - 1)) { + value = buf_p + sizeof(SETLOCALDEFS) - 1; + intptr = &load_setlocaldefs; + } else if (!strncmp(buf_p, REQUIRESEUSERS, + sizeof(REQUIRESEUSERS) - 1)) { + value = buf_p + sizeof(REQUIRESEUSERS) - 1; + intptr = &require_seusers; + } else { + continue; + } + + if (isdigit(*value)) + *intptr = atoi(value); + else if (strncasecmp(value, "true", sizeof("true") - 1)) + *intptr = 1; + else if (strncasecmp + (value, "false", sizeof("false") - 1)) + *intptr = 0; + } + free(line_buf); + fclose(fp); + } + + if (!type) { + selinux_policytype = type = strdup(SELINUXDEFAULT); + if (!type) + return; + } + + if (asprintf(&selinux_policyroot, "%s%s", SELINUXDIR, type) == -1) + return; + + for (i = 0; i < NEL; i++) + if (asprintf(&file_paths[i], "%s%s", + selinux_policyroot, + file_path_suffixes_data.str + + file_path_suffixes_idx[i]) + == -1) + return; +} + +static void fini_selinux_policyroot(void) __attribute__ ((destructor)); + +static void fini_selinux_policyroot(void) +{ + int i; + free(selinux_policyroot); + selinux_policyroot = NULL; + for (i = 0; i < NEL; i++) { + free(file_paths[i]); + file_paths[i] = NULL; + } + free(selinux_policytype); + selinux_policytype = NULL; +} + +void selinux_reset_config(void) +{ + fini_selinux_policyroot(); + init_selinux_config(); +} + +hidden_def(selinux_reset_config) + +static const char *get_path(int idx) +{ + __selinux_once(once, init_selinux_config); + return file_paths[idx]; +} + +const char *selinux_default_type_path(void) +{ + return get_path(DEFAULT_TYPE); +} + +hidden_def(selinux_default_type_path) + +const char *selinux_policy_root(void) +{ + __selinux_once(once, init_selinux_config); + return selinux_policyroot; +} + +int selinux_set_policy_root(const char *path) +{ + int i; + char *policy_type = strrchr(path, '/'); + if (!policy_type) { + errno = EINVAL; + return -1; + } + policy_type++; + + fini_selinuxmnt(); + fini_selinux_policyroot(); + + selinux_policyroot = strdup(path); + if (! selinux_policyroot) + return -1; + + if (setpolicytype(policy_type) != 0) + return -1; + + for (i = 0; i < NEL; i++) + if (asprintf(&file_paths[i], "%s%s", + selinux_policyroot, + file_path_suffixes_data.str + + file_path_suffixes_idx[i]) + == -1) + return -1; + + return 0; +} + +const char *selinux_path(void) +{ + return selinux_rootpath; +} + +hidden_def(selinux_path) + +const char *selinux_default_context_path(void) +{ + return get_path(DEFAULT_CONTEXTS); +} + +hidden_def(selinux_default_context_path) + +const char *selinux_securetty_types_path(void) +{ + return get_path(SECURETTY_TYPES); +} + +hidden_def(selinux_securetty_types_path) + +const char *selinux_failsafe_context_path(void) +{ + return get_path(FAILSAFE_CONTEXT); +} + +hidden_def(selinux_failsafe_context_path) + +const char *selinux_removable_context_path(void) +{ + return get_path(REMOVABLE_CONTEXT); +} + +hidden_def(selinux_removable_context_path) + +const char *selinux_binary_policy_path(void) +{ + return get_path(BINPOLICY); +} + +hidden_def(selinux_binary_policy_path) + +const char *selinux_current_policy_path(void) +{ + int rc = 0; + int vers = 0; + static char policy_path[PATH_MAX]; + + if (selinux_mnt) { + snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt); + if (access(policy_path, F_OK) == 0 ) { + return policy_path; + } + } + vers = security_policyvers(); + do { + /* Check prior versions to see if old policy is available */ + snprintf(policy_path, sizeof(policy_path), "%s.%d", + selinux_binary_policy_path(), vers); + } while ((rc = access(policy_path, F_OK)) && --vers > 0); + + if (rc) return NULL; + return policy_path; +} + +hidden_def(selinux_current_policy_path) + +const char *selinux_file_context_path(void) +{ + return get_path(FILE_CONTEXTS); +} + +hidden_def(selinux_file_context_path) + +const char *selinux_homedir_context_path(void) +{ + return get_path(HOMEDIR_CONTEXTS); +} + +hidden_def(selinux_homedir_context_path) + +const char *selinux_media_context_path(void) +{ + return get_path(MEDIA_CONTEXTS); +} + +hidden_def(selinux_media_context_path) + +const char *selinux_customizable_types_path(void) +{ + return get_path(CUSTOMIZABLE_TYPES); +} + +hidden_def(selinux_customizable_types_path) + +const char *selinux_contexts_path(void) +{ + return get_path(CONTEXTS_DIR); +} + +const char *selinux_user_contexts_path(void) +{ + return get_path(USER_CONTEXTS); +} + +hidden_def(selinux_user_contexts_path) + +const char *selinux_booleans_path(void) +{ + return get_path(BOOLEANS); +} + +hidden_def(selinux_booleans_path) + +const char *selinux_users_path(void) +{ + return get_path(USERS_DIR); +} + +hidden_def(selinux_users_path) + +const char *selinux_usersconf_path(void) +{ + return get_path(SEUSERS); +} + +hidden_def(selinux_usersconf_path) + +const char *selinux_translations_path(void) +{ + return get_path(TRANSLATIONS); +} + +hidden_def(selinux_translations_path) + +const char *selinux_colors_path(void) +{ + return get_path(COLORS); +} + +hidden_def(selinux_colors_path) + +const char *selinux_netfilter_context_path(void) +{ + return get_path(NETFILTER_CONTEXTS); +} + +hidden_def(selinux_netfilter_context_path) + +const char *selinux_file_context_homedir_path(void) +{ + return get_path(FILE_CONTEXTS_HOMEDIR); +} + +hidden_def(selinux_file_context_homedir_path) + +const char *selinux_file_context_local_path(void) +{ + return get_path(FILE_CONTEXTS_LOCAL); +} + +hidden_def(selinux_file_context_local_path) + +const char *selinux_x_context_path(void) +{ + return get_path(X_CONTEXTS); +} + +hidden_def(selinux_x_context_path) + +const char *selinux_virtual_domain_context_path(void) +{ + return get_path(VIRTUAL_DOMAIN); +} + +hidden_def(selinux_virtual_domain_context_path) + +const char *selinux_virtual_image_context_path(void) +{ + return get_path(VIRTUAL_IMAGE); +} + +hidden_def(selinux_virtual_image_context_path) + +const char *selinux_lxc_contexts_path(void) +{ + return get_path(LXC_CONTEXTS); +} + +hidden_def(selinux_lxc_contexts_path) + +const char *selinux_openssh_contexts_path(void) +{ + return get_path(OPENSSH_CONTEXTS); +} + +hidden_def(selinux_openssh_contexts_path) + +const char *selinux_systemd_contexts_path(void) +{ + return get_path(SYSTEMD_CONTEXTS); +} + +hidden_def(selinux_systemd_contexts_path) + +const char * selinux_booleans_subs_path(void) { + return get_path(BOOLEAN_SUBS); +} + +hidden_def(selinux_booleans_subs_path) + +const char * selinux_file_context_subs_path(void) { + return get_path(FILE_CONTEXT_SUBS); +} + +hidden_def(selinux_file_context_subs_path) + +const char * selinux_file_context_subs_dist_path(void) { + return get_path(FILE_CONTEXT_SUBS_DIST); +} + +hidden_def(selinux_file_context_subs_dist_path) + +const char *selinux_sepgsql_context_path(void) +{ + return get_path(SEPGSQL_CONTEXTS); +} + +hidden_def(selinux_sepgsql_context_path)
diff --git a/selinux/libselinux/src/selinux_internal.h b/selinux/libselinux/src/selinux_internal.h new file mode 100644 index 0000000..46566f6 --- /dev/null +++ b/selinux/libselinux/src/selinux_internal.h
@@ -0,0 +1,147 @@ +#include <selinux/selinux.h> +#include <pthread.h> +#include "dso.h" + +hidden_proto(selinux_mkload_policy) + hidden_proto(fini_selinuxmnt) + hidden_proto(set_selinuxmnt) + hidden_proto(selinuxfs_exists) + hidden_proto(security_disable) + hidden_proto(security_policyvers) + hidden_proto(security_load_policy) + hidden_proto(security_get_boolean_active) + hidden_proto(security_get_boolean_names) + hidden_proto(security_set_boolean) + hidden_proto(security_commit_booleans) + hidden_proto(security_check_context) + hidden_proto(security_check_context_raw) + hidden_proto(security_canonicalize_context) + hidden_proto(security_canonicalize_context_raw) + hidden_proto(security_compute_av) + hidden_proto(security_compute_av_raw) + hidden_proto(security_compute_av_flags) + hidden_proto(security_compute_av_flags_raw) + hidden_proto(security_compute_user) + hidden_proto(security_compute_user_raw) + hidden_proto(security_compute_create) + hidden_proto(security_compute_create_raw) + hidden_proto(security_compute_create_name) + hidden_proto(security_compute_create_name_raw) + hidden_proto(security_compute_member_raw) + hidden_proto(security_compute_relabel_raw) + hidden_proto(is_selinux_enabled) + hidden_proto(is_selinux_mls_enabled) + hidden_proto(freecon) + hidden_proto(freeconary) + hidden_proto(getprevcon) + hidden_proto(getprevcon_raw) + hidden_proto(getcon) + hidden_proto(getcon_raw) + hidden_proto(setcon_raw) + hidden_proto(getpeercon_raw) + hidden_proto(getpidcon_raw) + hidden_proto(getexeccon_raw) + hidden_proto(getfilecon) + hidden_proto(getfilecon_raw) + hidden_proto(lgetfilecon_raw) + hidden_proto(fgetfilecon_raw) + hidden_proto(setfilecon_raw) + hidden_proto(lsetfilecon_raw) + hidden_proto(fsetfilecon_raw) + hidden_proto(setexeccon) + hidden_proto(setexeccon_raw) + hidden_proto(getfscreatecon_raw) + hidden_proto(getkeycreatecon_raw) + hidden_proto(getsockcreatecon_raw) + hidden_proto(setfscreatecon_raw) + hidden_proto(setkeycreatecon_raw) + hidden_proto(setsockcreatecon_raw) + hidden_proto(security_getenforce) + hidden_proto(security_setenforce) + hidden_proto(security_deny_unknown) + hidden_proto(selinux_boolean_sub) + hidden_proto(selinux_current_policy_path) + hidden_proto(selinux_binary_policy_path) + hidden_proto(selinux_booleans_subs_path) + hidden_proto(selinux_default_context_path) + hidden_proto(selinux_securetty_types_path) + hidden_proto(selinux_failsafe_context_path) + hidden_proto(selinux_removable_context_path) + hidden_proto(selinux_virtual_domain_context_path) + hidden_proto(selinux_virtual_image_context_path) + hidden_proto(selinux_lxc_contexts_path) + hidden_proto(selinux_file_context_path) + hidden_proto(selinux_file_context_homedir_path) + hidden_proto(selinux_file_context_local_path) + hidden_proto(selinux_file_context_subs_dist_path) + hidden_proto(selinux_file_context_subs_path) + hidden_proto(selinux_netfilter_context_path) + hidden_proto(selinux_homedir_context_path) + hidden_proto(selinux_user_contexts_path) + hidden_proto(selinux_booleans_path) + hidden_proto(selinux_customizable_types_path) + hidden_proto(selinux_media_context_path) + hidden_proto(selinux_x_context_path) + hidden_proto(selinux_sepgsql_context_path) + hidden_proto(selinux_openssh_contexts_path) + hidden_proto(selinux_systemd_contexts_path) + hidden_proto(selinux_path) + hidden_proto(selinux_check_passwd_access) + hidden_proto(selinux_check_securetty_context) + hidden_proto(matchpathcon_init_prefix) + hidden_proto(selinux_users_path) + hidden_proto(selinux_usersconf_path); +hidden_proto(selinux_translations_path); +hidden_proto(selinux_colors_path); +hidden_proto(selinux_getenforcemode); +hidden_proto(selinux_getpolicytype); +hidden_proto(selinux_raw_to_trans_context); +hidden_proto(selinux_trans_to_raw_context); + hidden_proto(selinux_raw_context_to_color); +hidden_proto(security_get_initial_context); +hidden_proto(security_get_initial_context_raw); +hidden_proto(selinux_reset_config); + +hidden void flush_class_cache(void); + +extern int load_setlocaldefs hidden; +extern int require_seusers hidden; +extern int selinux_page_size hidden; + +/* Make pthread_once optional */ +#pragma weak pthread_once +#pragma weak pthread_key_create +#pragma weak pthread_key_delete +#pragma weak pthread_setspecific + +/* Call handler iff the first call. */ +#define __selinux_once(ONCE_CONTROL, INIT_FUNCTION) \ + do { \ + if (pthread_once != NULL) \ + pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) = 2; \ + } \ + } while (0) + +/* Pthread key macros */ +#define __selinux_key_create(KEY, DESTRUCTOR) \ + (pthread_key_create != NULL ? pthread_key_create(KEY, DESTRUCTOR) : -1) + +#define __selinux_key_delete(KEY) \ + do { \ + if (pthread_key_delete != NULL) \ + pthread_key_delete(KEY); \ + } while (0) + +#define __selinux_setspecific(KEY, VALUE) \ + do { \ + if (pthread_setspecific != NULL) \ + pthread_setspecific(KEY, VALUE); \ + } while (0) + +#define SELINUXDIR "/etc/selinux/" +#define SELINUXCONFIG SELINUXDIR "config" + +extern int has_selinux_config hidden;
diff --git a/selinux/libselinux/src/selinux_netlink.h b/selinux/libselinux/src/selinux_netlink.h new file mode 100644 index 0000000..88ef551 --- /dev/null +++ b/selinux/libselinux/src/selinux_netlink.h
@@ -0,0 +1,31 @@ +/* + * Netlink event notifications for SELinux. + * + * Author: James Morris <jmorris@redhat.com> + */ +#ifndef _LINUX_SELINUX_NETLINK_H +#define _LINUX_SELINUX_NETLINK_H + +/* Message types. */ +#define SELNL_MSG_BASE 0x10 +enum { + SELNL_MSG_SETENFORCE = SELNL_MSG_BASE, + SELNL_MSG_POLICYLOAD, + SELNL_MSG_MAX +}; + +/* Multicast groups */ +#define SELNL_GRP_NONE 0x00000000 +#define SELNL_GRP_AVC 0x00000001 /* AVC notifications */ +#define SELNL_GRP_ALL 0xffffffff + +/* Message structures */ +struct selnl_msg_setenforce { + int32_t val; +}; + +struct selnl_msg_policyload { + uint32_t seqno; +}; + +#endif /* _LINUX_SELINUX_NETLINK_H */
diff --git a/selinux/libselinux/src/selinux_restorecon.c b/selinux/libselinux/src/selinux_restorecon.c new file mode 100644 index 0000000..17ed6fe --- /dev/null +++ b/selinux/libselinux/src/selinux_restorecon.c
@@ -0,0 +1,486 @@ +/* + * The majority of this code is from Android's + * external/libselinux/src/android.c and upstream + * selinux/policycoreutils/setfiles/restorecon.c + * + * See selinux_restorecon(3) for details. + */ + +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/xattr.h> +#include <sys/vfs.h> +#include <linux/magic.h> +#include <libgen.h> +#include <selinux/selinux.h> +#include <selinux/context.h> +#include <selinux/label.h> +#include <selinux/restorecon.h> + +#include "callbacks.h" +#include "selinux_internal.h" + +#define RESTORECON_LAST "security.restorecon_last" + +#define SYS_PATH "/sys" +#define SYS_PREFIX SYS_PATH "/" + +static struct selabel_handle *fc_sehandle = NULL; +static unsigned char *fc_digest = NULL; +static size_t fc_digest_len = 0; +static const char **fc_exclude_list = NULL; +static size_t fc_count = 0; +#define STAR_COUNT 1000 + +static void restorecon_init(void) +{ + struct selabel_handle *sehandle = NULL; + + if (!fc_sehandle) { + sehandle = selinux_restorecon_default_handle(); + selinux_restorecon_set_sehandle(sehandle); + } +} + +static pthread_once_t fc_once = PTHREAD_ONCE_INIT; + + +static int check_excluded(const char *file) +{ + int i; + + for (i = 0; fc_exclude_list[i]; i++) { + if (strcmp(file, fc_exclude_list[i]) == 0) + return 1; + } + return 0; +} + +/* Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if + * the type components differ, updating newtypecon if so. */ +static int compare_types(char *curcon, char *newcon, char **newtypecon) +{ + int types_differ = 0; + context_t cona; + context_t conb; + int rc = 0; + + cona = context_new(curcon); + if (!cona) { + rc = -1; + goto out; + } + conb = context_new(newcon); + if (!conb) { + context_free(cona); + rc = -1; + goto out; + } + + types_differ = strcmp(context_type_get(cona), context_type_get(conb)); + if (types_differ) { + rc |= context_user_set(conb, context_user_get(cona)); + rc |= context_role_set(conb, context_role_get(cona)); + rc |= context_range_set(conb, context_range_get(cona)); + if (!rc) { + *newtypecon = strdup(context_str(conb)); + if (!*newtypecon) { + rc = -1; + goto err; + } + } + } + +err: + context_free(cona); + context_free(conb); +out: + return rc; +} + +static int restorecon_sb(const char *pathname, const struct stat *sb, + bool nochange, bool verbose, + bool progress, bool specctx) +{ + char *newcon = NULL; + char *curcon = NULL; + char *newtypecon = NULL; + int rc = 0; + bool updated = false; + + if (selabel_lookup_raw(fc_sehandle, &newcon, pathname, sb->st_mode) < 0) + return 0; /* no match, but not an error */ + + if (lgetfilecon_raw(pathname, &curcon) < 0) { + if (errno != ENODATA) + goto err; + + curcon = NULL; + } + + if (progress) { + fc_count++; + if (fc_count % STAR_COUNT == 0) { + fprintf(stdout, "*"); + fflush(stdout); + } + } + + if (strcmp(curcon, newcon) != 0) { + if (!specctx && curcon && + (is_context_customizable(curcon) > 0)) { + if (verbose) { + selinux_log(SELINUX_INFO, + "%s not reset as customized by admin to %s\n", + pathname, curcon); + goto out; + } + } + + if (!specctx && curcon) { + /* If types different then update newcon. */ + rc = compare_types(curcon, newcon, &newtypecon); + if (rc) + goto err; + + if (newtypecon) { + freecon(newcon); + newcon = newtypecon; + } else { + goto out; + } + } + + if (!nochange) { + if (lsetfilecon(pathname, newcon) < 0) + goto err; + updated = true; + } + + if (verbose) + selinux_log(SELINUX_INFO, + "%s %s from %s to %s\n", + updated ? "Relabeled" : "Would relabel", + pathname, curcon, newcon); + } + +out: + rc = 0; +out1: + freecon(curcon); + freecon(newcon); + return rc; +err: + selinux_log(SELINUX_ERROR, + "Could not set context for %s: %s\n", + pathname, strerror(errno)); + rc = -1; + goto out1; +} + +/* + * Public API + */ + +/* selinux_restorecon(3) - Main function that is responsible for labeling */ +int selinux_restorecon(const char *pathname_orig, + unsigned int restorecon_flags) +{ + bool ignore = (restorecon_flags & + SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; + bool nochange = (restorecon_flags & + SELINUX_RESTORECON_NOCHANGE) ? true : false; + bool verbose = (restorecon_flags & + SELINUX_RESTORECON_VERBOSE) ? true : false; + bool progress = (restorecon_flags & + SELINUX_RESTORECON_PROGRESS) ? true : false; + bool recurse = (restorecon_flags & + SELINUX_RESTORECON_RECURSE) ? true : false; + bool specctx = (restorecon_flags & + SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; + bool userealpath = (restorecon_flags & + SELINUX_RESTORECON_REALPATH) ? true : false; + bool xdev = (restorecon_flags & + SELINUX_RESTORECON_XDEV) ? true : false; + bool issys; + bool setrestoreconlast = true; /* TRUE = set xattr RESTORECON_LAST + * FALSE = don't use xattr */ + struct stat sb; + struct statfs sfsb; + FTS *fts; + FTSENT *ftsent; + char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; + char *paths[2] = { NULL , NULL }; + int fts_flags; + int error, sverrno; + char *xattr_value = NULL; + ssize_t size; + + if (verbose && progress) + verbose = false; + + __selinux_once(fc_once, restorecon_init); + + if (!fc_sehandle) + return -1; + + if (fc_digest_len) { + xattr_value = malloc(fc_digest_len); + if (!xattr_value) + return -1; + } + + /* + * Convert passed-in pathname to canonical pathname by resolving + * realpath of containing dir, then appending last component name. + */ + if (userealpath) { + pathbname = basename((char *)pathname_orig); + if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || + !strcmp(pathbname, "..")) { + pathname = realpath(pathname_orig, NULL); + if (!pathname) + goto realpatherr; + } else { + pathdname = dirname((char *)pathname_orig); + pathdnamer = realpath(pathdname, NULL); + if (!pathdnamer) + goto realpatherr; + if (!strcmp(pathdnamer, "/")) + error = asprintf(&pathname, "/%s", pathbname); + else + error = asprintf(&pathname, "%s/%s", + pathdnamer, pathbname); + if (error < 0) + goto oom; + } + } else { + pathname = strdup(pathname_orig); + if (!pathname) + goto oom; + } + + paths[0] = pathname; + issys = (!strcmp(pathname, SYS_PATH) || + !strncmp(pathname, SYS_PREFIX, + sizeof(SYS_PREFIX) - 1)) ? true : false; + + if (lstat(pathname, &sb) < 0) { + error = -1; + goto cleanup; + } + + /* Ignore restoreconlast if not a directory */ + if ((sb.st_mode & S_IFDIR) != S_IFDIR) + setrestoreconlast = false; + + if (!recurse) { + error = restorecon_sb(pathname, &sb, nochange, verbose, + progress, specctx); + goto cleanup; + } + + /* Ignore restoreconlast on /sys */ + if (issys) + setrestoreconlast = false; + + /* Ignore restoreconlast on in-memory filesystems */ + if (statfs(pathname, &sfsb) == 0) { + if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC) + setrestoreconlast = false; + } + + if (setrestoreconlast) { + size = getxattr(pathname, RESTORECON_LAST, xattr_value, + fc_digest_len); + + if (!ignore && size == fc_digest_len && + memcmp(fc_digest, xattr_value, fc_digest_len) + == 0) { + selinux_log(SELINUX_INFO, + "Skipping restorecon as matching digest on: %s\n", + pathname); + error = 0; + goto cleanup; + } + } + + if (xdev) + fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; + else + fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) { + error = -1; + goto cleanup; + } + + error = 0; + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_DC: + selinux_log(SELINUX_ERROR, + "Directory cycle on %s.\n", + ftsent->fts_path); + errno = ELOOP; + error = -1; + goto out; + case FTS_DP: + continue; + case FTS_DNR: + selinux_log(SELINUX_ERROR, + "Could not read %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_NS: + selinux_log(SELINUX_ERROR, + "Could not stat %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_ERR: + selinux_log(SELINUX_ERROR, + "Error on %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_D: + if (issys && !selabel_partial_match(fc_sehandle, + ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + /* fall through */ + default: + if (fc_exclude_list) { + if (check_excluded(ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + } + + error |= restorecon_sb(ftsent->fts_path, + ftsent->fts_statp, nochange, + verbose, progress, specctx); + break; + } + } + + /* Labeling successful. Mark the top level directory as completed. */ + if (setrestoreconlast && !nochange && !error) { + error = setxattr(pathname, RESTORECON_LAST, fc_digest, + fc_digest_len, 0); + if (!error && verbose) + selinux_log(SELINUX_INFO, + "Updated digest for: %s\n", pathname); + } + +out: + sverrno = errno; + (void) fts_close(fts); + errno = sverrno; +cleanup: + free(pathdnamer); + free(pathname); + free(xattr_value); + return error; +oom: + sverrno = errno; + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + errno = sverrno; + error = -1; + goto cleanup; +realpatherr: + sverrno = errno; + selinux_log(SELINUX_ERROR, + "SELinux: Could not get canonical path for %s restorecon: %s.\n", + pathname_orig, strerror(errno)); + errno = sverrno; + error = -1; + goto cleanup; +} + +/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ +void selinux_restorecon_set_sehandle(struct selabel_handle *hndl) +{ + char **specfiles, *sha1_buf = NULL; + size_t num_specfiles, i; + + fc_sehandle = (struct selabel_handle *) hndl; + + /* Read digest if requested in selabel_open(3). + * If not the set global params. */ + if (selabel_digest(hndl, &fc_digest, &fc_digest_len, + &specfiles, &num_specfiles) < 0) { + fc_digest = NULL; + fc_digest_len = 0; + selinux_log(SELINUX_INFO, "Digest not requested.\n"); + return; + } + + sha1_buf = malloc(fc_digest_len * 2 + 1); + if (!sha1_buf) { + selinux_log(SELINUX_ERROR, + "Error allocating digest buffer: %s\n", + strerror(errno)); + return; + } + + for (i = 0; i < fc_digest_len; i++) + sprintf((&sha1_buf[i * 2]), "%02x", fc_digest[i]); + + selinux_log(SELINUX_INFO, + "specfiles SHA1 digest: %s\n", sha1_buf); + selinux_log(SELINUX_INFO, + "calculated using the following specfile(s):\n"); + if (specfiles) { + for (i = 0; i < num_specfiles; i++) + selinux_log(SELINUX_INFO, + "%s\n", specfiles[i]); + } + free(sha1_buf); +} + +/* selinux_restorecon_default_handle(3) is called to set the global restorecon + * handle by a process if the default params are required. */ +struct selabel_handle *selinux_restorecon_default_handle(void) +{ + struct selabel_handle *sehandle; + + struct selinux_opt fc_opts[] = { + { SELABEL_OPT_DIGEST, (char *)1 } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 1); + + if (!sehandle) { + selinux_log(SELINUX_ERROR, + "Error obtaining file context handle: %s\n", + strerror(errno)); + return NULL; + } + + return sehandle; +} + +/* selinux_restorecon_set_exclude_list(3) is called to set a NULL terminated + * list of files/directories to exclude. */ +void selinux_restorecon_set_exclude_list(const char **exclude_list) +{ + fc_exclude_list = exclude_list; +}
diff --git a/selinux/libselinux/src/selinuxswig.i b/selinux/libselinux/src/selinuxswig.i new file mode 100644 index 0000000..c1e4ef7 --- /dev/null +++ b/selinux/libselinux/src/selinuxswig.i
@@ -0,0 +1,64 @@ +/* Authors: Dan Walsh + * James Athey + */ + +%module selinux +%{ + #include "../include/selinux/avc.h" + #include "../include/selinux/context.h" + #include "../include/selinux/get_context_list.h" + #include "../include/selinux/get_default_type.h" + #include "../include/selinux/label.h" + #include "../include/selinux/selinux.h" +%} +%apply int *OUTPUT { int *enforce }; +%apply int *OUTPUT { size_t * }; + +%typedef unsigned mode_t; +%typedef unsigned pid_t; + +%typemap(in, numinputs=0) (char ***names, int *len) (char **temp1, int temp2) { + $1 = &temp1; + $2 = &temp2; +} + +%typemap(freearg) (char ***names, int *len) { + int i; + if (*$1) { + for (i = 0; i < *$2; i++) { + free((*$1)[i]); + } + free(*$1); + } +} + +%typemap(in, numinputs=0) (char ***) (char **temp) { + $1 = &temp; +} + +%typemap(freearg) (char ***) { + if (*$1) freeconary(*$1); +} + +/* Ignore functions that don't make sense when wrapped */ +%ignore freecon; +%ignore freeconary; + +/* Ignore functions that take a function pointer as an argument */ +%ignore set_matchpathcon_printf; +%ignore set_matchpathcon_invalidcon; +%ignore set_matchpathcon_canoncon; + +%ignore avc_add_callback; + +/* Ignore netlink stuff for now */ +%ignore avc_netlink_acquire_fd; +%ignore avc_netlink_release_fd; +%ignore avc_netlink_check_nb; + +%include "../include/selinux/avc.h" +%include "../include/selinux/context.h" +%include "../include/selinux/get_context_list.h" +%include "../include/selinux/get_default_type.h" +%include "../include/selinux/label.h" +%include "../include/selinux/selinux.h"
diff --git a/selinux/libselinux/src/selinuxswig_python.i b/selinux/libselinux/src/selinuxswig_python.i new file mode 100644 index 0000000..8cea18d --- /dev/null +++ b/selinux/libselinux/src/selinuxswig_python.i
@@ -0,0 +1,202 @@ +/* Author: James Athey + */ + +%module selinux +%{ + #include "selinux/selinux.h" +%} + +%pythoncode %{ + +import shutil, os, errno, stat + +DISABLED = -1 +PERMISSIVE = 0 +ENFORCING = 1 + +def restorecon(path, recursive=False): + """ Restore SELinux context on a given path """ + + try: + mode = os.lstat(path)[stat.ST_MODE] + status, context = matchpathcon(path, mode) + except OSError: + path = os.path.realpath(os.path.expanduser(path)) + mode = os.lstat(path)[stat.ST_MODE] + status, context = matchpathcon(path, mode) + + if status == 0: + try: + status, oldcontext = lgetfilecon(path) + except OSError as e: + if e.errno != errno.ENODATA: + raise + oldcontext = None + if context != oldcontext: + lsetfilecon(path, context) + + if recursive: + for root, dirs, files in os.walk(path): + for name in files + dirs: + restorecon(os.path.join(root, name)) + +def chcon(path, context, recursive=False): + """ Set the SELinux context on a given path """ + lsetfilecon(path, context) + if recursive: + for root, dirs, files in os.walk(path): + for name in files + dirs: + lsetfilecon(os.path.join(root,name), context) + +def copytree(src, dest): + """ An SELinux-friendly shutil.copytree method """ + shutil.copytree(src, dest) + restorecon(dest, recursive=True) + +def install(src, dest): + """ An SELinux-friendly shutil.move method """ + shutil.move(src, dest) + restorecon(dest, recursive=True) +%} + +/* security_get_boolean_names() typemap */ +%typemap(argout) (char ***names, int *len) { + PyObject* list = PyList_New(*$2); + int i; + for (i = 0; i < *$2; i++) { + PyList_SetItem(list, i, PyBytes_FromString((*$1)[i])); + } + $result = SWIG_Python_AppendOutput($result, list); +} + +/* return a sid along with the result */ +%typemap(argout) (security_id_t * sid) { + if (*$1) { + %append_output(SWIG_NewPointerObj(*$1, $descriptor(security_id_t), 0)); + } else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%typemap(in,numinputs=0) security_id_t *(security_id_t temp) { + $1 = &temp; +} + +%typemap(in, numinputs=0) void *(char *temp=NULL) { + $1 = temp; +} + +/* Makes security_compute_user() return a Python list of contexts */ +%typemap(argout) (char ***con) { + PyObject* plist; + int i, len = 0; + + if (*$1) { + while((*$1)[len]) + len++; + plist = PyList_New(len); + for (i = 0; i < len; i++) { + PyList_SetItem(plist, i, + PyBytes_FromString((*$1)[i]) + ); + } + } else { + plist = PyList_New(0); + } + + $result = SWIG_Python_AppendOutput($result, plist); +} + +/* Makes functions in get_context_list.h return a Python list of contexts */ +%typemap(argout) (char ***list) { + PyObject* plist; + int i; + + if (*$1) { + plist = PyList_New(result); + for (i = 0; i < result; i++) { + PyList_SetItem(plist, i, + PyBytes_FromString((*$1)[i]) + ); + } + } else { + plist = PyList_New(0); + } + /* Only return the Python list, don't need to return the length anymore */ + $result = plist; +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + freecon(*$1); + } + else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + free(*$1); + } + else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%typemap(in) char * const [] { + int i, size; + PyObject * s; + + if (!PySequence_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expected a sequence"); + return NULL; + } + + size = PySequence_Size($input); + + $1 = (char**) malloc(size + 1); + + for(i = 0; i < size; i++) { + if (!PyBytes_Check(PySequence_GetItem($input, i))) { + PyErr_SetString(PyExc_ValueError, "Sequence must contain only bytes"); + + return NULL; + } + + } + + for(i = 0; i < size; i++) { + s = PySequence_GetItem($input, i); + + $1[i] = (char*) malloc(PyBytes_Size(s) + 1); + strcpy($1[i], PyBytes_AsString(s)); + + } + $1[size] = NULL; +} + +%typemap(freearg,match="in") char * const [] { + int i = 0; + while($1[i]) { + free($1[i]); + i++; + } + free($1); +} + +%include "selinuxswig_python_exception.i" +%include "selinuxswig.i"
diff --git a/selinux/libselinux/src/selinuxswig_ruby.i b/selinux/libselinux/src/selinuxswig_ruby.i new file mode 100644 index 0000000..12d63c4 --- /dev/null +++ b/selinux/libselinux/src/selinuxswig_ruby.i
@@ -0,0 +1,52 @@ +/* Author: Dan Walsh + Based on selinuxswig_python.i by James Athey + */ + +%module selinux +%{ + #include "selinux/selinux.h" +%} + +/* return a sid along with the result */ +%typemap(argout) (security_id_t * sid) { + if (*$1) { + %append_output(SWIG_NewPointerObj(*$1, $descriptor(security_id_t), 0)); + } +} + +%typemap(in,numinputs=0) security_id_t *(security_id_t temp) { + $1 = &temp; +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + freecon(*$1); + } +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + free(*$1); + } +} + +%typemap(freearg,match="in") char * const [] { + int i = 0; + while($1[i]) { + free($1[i]); + i++; + } + free($1); +} + +%include "selinuxswig.i"
diff --git a/selinux/libselinux/src/sestatus.c b/selinux/libselinux/src/sestatus.c new file mode 100644 index 0000000..ed29dc5 --- /dev/null +++ b/selinux/libselinux/src/sestatus.c
@@ -0,0 +1,349 @@ +/* + * sestatus.c + * + * APIs to reference SELinux kernel status page (/selinux/status) + * + * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> + * + */ +#include <fcntl.h> +#include <limits.h> +#include <sched.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "avc_internal.h" +#include "policy.h" + +/* + * copied from the selinux/include/security.h + */ +struct selinux_status_t +{ + uint32_t version; /* version number of thie structure */ + uint32_t sequence; /* sequence number of seqlock logic */ + uint32_t enforcing; /* current setting of enforcing mode */ + uint32_t policyload; /* times of policy reloaded */ + uint32_t deny_unknown; /* current setting of deny_unknown */ + /* version > 0 support above status */ +} __attribute((packed)); + +/* + * `selinux_status' + * + * NULL : not initialized yet + * MAP_FAILED : opened, but fallback-mode + * Valid Pointer : opened and mapped correctly + */ +static struct selinux_status_t *selinux_status = NULL; +static int selinux_status_fd; +static uint32_t last_seqno; + +static uint32_t fallback_sequence; +static int fallback_enforcing; +static int fallback_policyload; + +/* + * read_sequence + * + * A utility routine to reference kernel status page according to + * seqlock logic. Since selinux_status->sequence is an odd value during + * the kernel status page being updated, we try to synchronize completion + * of this updating, but we assume it is rare. + * The sequence is almost even number. + * + * __sync_synchronize is a portable memory barrier for various kind + * of architecture that is supported by GCC. + */ +static inline uint32_t read_sequence(struct selinux_status_t *status) +{ + uint32_t seqno = 0; + + do { + /* + * No need for sched_yield() in the first trial of + * this loop. + */ + if (seqno & 0x0001) + sched_yield(); + + seqno = status->sequence; + + __sync_synchronize(); + + } while (seqno & 0x0001); + + return seqno; +} + +/* + * selinux_status_updated + * + * It returns whether something has been happened since the last call. + * Because `selinux_status->sequence' shall be always incremented on + * both of setenforce/policyreload events, so differences from the last + * value informs us something has been happened. + */ +int selinux_status_updated(void) +{ + uint32_t curr_seqno; + int result = 0; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + curr_seqno = fallback_sequence; + } else { + curr_seqno = read_sequence(selinux_status); + } + + /* + * `curr_seqno' is always even-number, so it does not match with + * `last_seqno' being initialized to odd-number in the first call. + * We never return 'something was updated' in the first call, + * because this function focuses on status-updating since the last + * invocation. + */ + if (last_seqno & 0x0001) + last_seqno = curr_seqno; + + if (last_seqno != curr_seqno) + { + last_seqno = curr_seqno; + result = 1; + } + return result; +} + +/* + * selinux_status_getenforce + * + * It returns the current performing mode of SELinux. + * 1 means currently we run in enforcing mode, or 0 means permissive mode. + */ +int selinux_status_getenforce(void) +{ + uint32_t seqno; + uint32_t enforcing; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + return fallback_enforcing; + } + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + enforcing = selinux_status->enforcing; + + } while (seqno != read_sequence(selinux_status)); + + return enforcing ? 1 : 0; +} + +/* + * selinux_status_policyload + * + * It returns times of policy reloaded on the running system. + * Note that it is not a reliable value on fallback-mode until it receives + * the first event message via netlink socket, so, a correct usage of this + * value is to compare it with the previous value to detect policy reloaded + * event. + */ +int selinux_status_policyload(void) +{ + uint32_t seqno; + uint32_t policyload; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + return fallback_policyload; + } + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + policyload = selinux_status->policyload; + + } while (seqno != read_sequence(selinux_status)); + + return policyload; +} + +/* + * selinux_status_deny_unknown + * + * It returns a guideline to handle undefined object classes or permissions. + * 0 means SELinux treats policy queries on undefined stuff being allowed, + * however, 1 means such queries are denied. + */ +int selinux_status_deny_unknown(void) +{ + uint32_t seqno; + uint32_t deny_unknown; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) + return security_deny_unknown(); + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + deny_unknown = selinux_status->deny_unknown; + + } while (seqno != read_sequence(selinux_status)); + + return deny_unknown ? 1 : 0; +} + +/* + * callback routines for fallback case using netlink socket + */ +static int fallback_cb_setenforce(int enforcing) +{ + fallback_sequence += 2; + fallback_enforcing = enforcing; + + return 0; +} + +static int fallback_cb_policyload(int policyload) +{ + fallback_sequence += 2; + fallback_policyload = policyload; + + return 0; +} + +/* + * selinux_status_open + * + * It tries to open and mmap kernel status page (/selinux/status). + * Since Linux 2.6.37 or later supports this feature, we may run + * fallback routine using a netlink socket on older kernels, if + * the supplied `fallback' is not zero. + * It returns 0 on success, or -1 on error. + */ +int selinux_status_open(int fallback) +{ + int fd; + char path[PATH_MAX]; + long pagesize; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize < 0) + return -1; + + snprintf(path, sizeof(path), "%s/status", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto error; + + selinux_status = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); + if (selinux_status == MAP_FAILED) { + close(fd); + goto error; + } + selinux_status_fd = fd; + last_seqno = (uint32_t)(-1); + + return 0; + +error: + /* + * If caller wants fallback routine, we try to provide + * an equivalent functionality using existing netlink + * socket, although it needs system call invocation to + * receive event notification. + */ + if (fallback && avc_netlink_open(0) == 0) { + union selinux_callback cb; + + /* register my callbacks */ + cb.func_setenforce = fallback_cb_setenforce; + selinux_set_callback(SELINUX_CB_SETENFORCE, cb); + cb.func_policyload = fallback_cb_policyload; + selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); + + /* mark as fallback mode */ + selinux_status = MAP_FAILED; + selinux_status_fd = avc_netlink_acquire_fd(); + last_seqno = (uint32_t)(-1); + + fallback_sequence = 0; + fallback_enforcing = security_getenforce(); + fallback_policyload = 0; + + return 1; + } + selinux_status = NULL; + + return -1; +} + +/* + * selinux_status_close + * + * It unmap and close the kernel status page, or close netlink socket + * if fallback mode. + */ +void selinux_status_close(void) +{ + long pagesize; + + /* not opened */ + if (selinux_status == NULL) + return; + + /* fallback-mode */ + if (selinux_status == MAP_FAILED) + { + avc_netlink_release_fd(); + avc_netlink_close(); + selinux_status = NULL; + return; + } + + pagesize = sysconf(_SC_PAGESIZE); + /* not much we can do other than leak memory */ + if (pagesize > 0) + munmap(selinux_status, pagesize); + selinux_status = NULL; + + close(selinux_status_fd); + selinux_status_fd = -1; + last_seqno = (uint32_t)(-1); +}
diff --git a/selinux/libselinux/src/setenforce.c b/selinux/libselinux/src/setenforce.c new file mode 100644 index 0000000..e5e7612 --- /dev/null +++ b/selinux/libselinux/src/setenforce.c
@@ -0,0 +1,37 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include "selinux_internal.h" +#include "policy.h" +#include <stdio.h> +#include <limits.h> + +int security_setenforce(int value) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/enforce", selinux_mnt); + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + snprintf(buf, sizeof buf, "%d", value); + ret = write(fd, buf, strlen(buf)); + close(fd); + if (ret < 0) + return -1; + + return 0; +} + +hidden_def(security_setenforce)
diff --git a/selinux/libselinux/src/setexecfilecon.c b/selinux/libselinux/src/setexecfilecon.c new file mode 100644 index 0000000..e72ba0d --- /dev/null +++ b/selinux/libselinux/src/setexecfilecon.c
@@ -0,0 +1,70 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include "selinux_internal.h" +#include "context_internal.h" + +int setexecfilecon(const char *filename, const char *fallback_type) +{ + char * mycon = NULL, *fcon = NULL, *newcon = NULL; + context_t con = NULL; + int rc = 0; + + if (is_selinux_enabled() < 1) + return 0; + + rc = getcon(&mycon); + if (rc < 0) + goto out; + + rc = getfilecon(filename, &fcon); + if (rc < 0) + goto out; + + rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &newcon); + if (rc < 0) + goto out; + + if (!strcmp(mycon, newcon)) { + /* No default transition, use fallback_type for now. */ + rc = -1; + con = context_new(mycon); + if (!con) + goto out; + if (context_type_set(con, fallback_type)) + goto out; + freecon(newcon); + newcon = strdup(context_str(con)); + if (!newcon) + goto out; + rc = 0; + } + + rc = setexeccon(newcon); + if (rc < 0) + goto out; + out: + + if (rc < 0 && security_getenforce() == 0) + rc = 0; + + context_free(con); + freecon(newcon); + freecon(fcon); + freecon(mycon); + return rc < 0 ? rc : 0; +} + +#ifndef DISABLE_RPM +int rpm_execcon(unsigned int verified __attribute__ ((unused)), + const char *filename, char *const argv[], char *const envp[]) +{ + int rc; + + rc = setexecfilecon(filename, "rpm_script_t"); + if (rc < 0) + return rc; + + return execve(filename, argv, envp); +} +#endif
diff --git a/selinux/libselinux/src/setfilecon.c b/selinux/libselinux/src/setfilecon.c new file mode 100644 index 0000000..d05969c --- /dev/null +++ b/selinux/libselinux/src/setfilecon.c
@@ -0,0 +1,43 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/xattr.h> +#include "selinux_internal.h" +#include "policy.h" + +int setfilecon_raw(const char *path, const char * context) +{ + int rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, + 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((getfilecon_raw(path, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(setfilecon_raw) + +int setfilecon(const char *path, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = setfilecon_raw(path, rcontext); + + freecon(rcontext); + + return ret; +}
diff --git a/selinux/libselinux/src/setrans_client.c b/selinux/libselinux/src/setrans_client.c new file mode 100644 index 0000000..8c3a41c --- /dev/null +++ b/selinux/libselinux/src/setrans_client.c
@@ -0,0 +1,443 @@ +/* Author: Trusted Computer Solutions, Inc. + * + * Modified: + * Yuichi Nakamura <ynakam@hitachisoft.jp> + - Stubs are used when DISABLE_SETRANS is defined, + it is to reduce size for such as embedded devices. +*/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <errno.h> +#include <stdlib.h> +#include <netdb.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include "dso.h" +#include "selinux_internal.h" +#include "setrans_internal.h" + +#ifndef DISABLE_SETRANS +static unsigned char has_setrans; + +// Simple cache +static __thread char * prev_t2r_trans = NULL; +static __thread char * prev_t2r_raw = NULL; +static __thread char * prev_r2t_trans = NULL; +static __thread char * prev_r2t_raw = NULL; +static __thread char *prev_r2c_trans = NULL; +static __thread char * prev_r2c_raw = NULL; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; +static __thread char destructor_initialized; + +/* + * setransd_open + * + * This function opens a socket to the setransd. + * Returns: on success, a file descriptor ( >= 0 ) to the socket + * on error, a negative value + */ +static int setransd_open(void) +{ + struct sockaddr_un addr; + int fd; +#ifdef SOCK_CLOEXEC + fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (fd < 0 && errno == EINVAL) +#endif + { + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd >= 0) + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + close(fd); + return -1; + } + } + if (fd < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path)); + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(fd); + return -1; + } + + return fd; +} + +/* Returns: 0 on success, <0 on failure */ +static int +send_request(int fd, uint32_t function, const char *data1, const char *data2) +{ + struct msghdr msgh; + struct iovec iov[5]; + uint32_t data1_size; + uint32_t data2_size; + ssize_t count, expected; + unsigned int i; + + if (fd < 0) + return -1; + + if (!data1) + data1 = ""; + if (!data2) + data2 = ""; + + data1_size = strlen(data1) + 1; + data2_size = strlen(data2) + 1; + + iov[0].iov_base = &function; + iov[0].iov_len = sizeof(function); + iov[1].iov_base = &data1_size; + iov[1].iov_len = sizeof(data1_size); + iov[2].iov_base = &data2_size; + iov[2].iov_len = sizeof(data2_size); + iov[3].iov_base = (char *)data1; + iov[3].iov_len = data1_size; + iov[4].iov_base = (char *)data2; + iov[4].iov_len = data2_size; + memset(&msgh, 0, sizeof(msgh)); + msgh.msg_iov = iov; + msgh.msg_iovlen = sizeof(iov) / sizeof(iov[0]); + + expected = 0; + for (i = 0; i < sizeof(iov) / sizeof(iov[0]); i++) + expected += iov[i].iov_len; + + while (((count = sendmsg(fd, &msgh, MSG_NOSIGNAL)) < 0) + && (errno == EINTR)) ; + if (count < 0 || count != expected) + return -1; + + return 0; +} + +/* Returns: 0 on success, <0 on failure */ +static int +receive_response(int fd, uint32_t function, char **outdata, int32_t * ret_val) +{ + struct iovec resp_hdr[3]; + uint32_t func; + uint32_t data_size; + char *data; + struct iovec resp_data; + ssize_t count; + + if (fd < 0) + return -1; + + resp_hdr[0].iov_base = &func; + resp_hdr[0].iov_len = sizeof(func); + resp_hdr[1].iov_base = &data_size; + resp_hdr[1].iov_len = sizeof(data_size); + resp_hdr[2].iov_base = ret_val; + resp_hdr[2].iov_len = sizeof(*ret_val); + + while (((count = readv(fd, resp_hdr, 3)) < 0) && (errno == EINTR)) ; + if (count != (sizeof(func) + sizeof(data_size) + sizeof(*ret_val))) { + return -1; + } + + if (func != function || !data_size || data_size > MAX_DATA_BUF) { + return -1; + } + + data = malloc(data_size); + if (!data) + return -1; + /* coveriety doesn't realize that data will be initialized in readv */ + memset(data, 0, data_size); + + resp_data.iov_base = data; + resp_data.iov_len = data_size; + + while (((count = readv(fd, &resp_data, 1))) < 0 && (errno == EINTR)) ; + if (count < 0 || (uint32_t) count != data_size || + data[data_size - 1] != '\0') { + free(data); + return -1; + } + *outdata = data; + return 0; +} + +static int raw_to_trans_context(const char *raw, char **transp) +{ + int ret; + int32_t ret_val; + int fd; + + *transp = NULL; + + fd = setransd_open(); + if (fd < 0) + return fd; + + ret = send_request(fd, RAW_TO_TRANS_CONTEXT, raw, NULL); + if (ret) + goto out; + + ret = receive_response(fd, RAW_TO_TRANS_CONTEXT, transp, &ret_val); + if (ret) + goto out; + + ret = ret_val; + out: + close(fd); + return ret; +} + +static int trans_to_raw_context(const char *trans, char **rawp) +{ + int ret; + int32_t ret_val; + int fd; + + *rawp = NULL; + + fd = setransd_open(); + if (fd < 0) + return fd; + ret = send_request(fd, TRANS_TO_RAW_CONTEXT, trans, NULL); + if (ret) + goto out; + + ret = receive_response(fd, TRANS_TO_RAW_CONTEXT, rawp, &ret_val); + if (ret) + goto out; + + ret = ret_val; + out: + close(fd); + return ret; +} + +static int raw_context_to_color(const char *raw, char **colors) +{ + int ret; + int32_t ret_val; + int fd; + + fd = setransd_open(); + if (fd < 0) + return fd; + + ret = send_request(fd, RAW_CONTEXT_TO_COLOR, raw, NULL); + if (ret) + goto out; + + ret = receive_response(fd, RAW_CONTEXT_TO_COLOR, colors, &ret_val); + if (ret) + goto out; + + ret = ret_val; +out: + close(fd); + return ret; +} + +static void setrans_thread_destructor(void __attribute__((unused)) *unused) +{ + free(prev_t2r_trans); + free(prev_t2r_raw); + free(prev_r2t_trans); + free(prev_r2t_raw); + free(prev_r2c_trans); + free(prev_r2c_raw); +} + +void __attribute__((destructor)) setrans_lib_destructor(void); + +void hidden __attribute__((destructor)) setrans_lib_destructor(void) +{ + if (!has_setrans) + return; + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static inline void init_thread_destructor(void) +{ + if (!has_setrans) + return; + if (destructor_initialized == 0) { + __selinux_setspecific(destructor_key, (void *)1); + destructor_initialized = 1; + } +} + +static void init_context_translations(void) +{ + has_setrans = (access(SETRANS_UNIX_SOCKET, F_OK) == 0); + if (!has_setrans) + return; + if (__selinux_key_create(&destructor_key, setrans_thread_destructor) == 0) + destructor_key_initialized = 1; +} + +int selinux_trans_to_raw_context(const char * trans, + char ** rawp) +{ + if (!trans) { + *rawp = NULL; + return 0; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *rawp = strdup(trans); + goto out; + } + + if (prev_t2r_trans && strcmp(prev_t2r_trans, trans) == 0) { + *rawp = strdup(prev_t2r_raw); + } else { + free(prev_t2r_trans); + prev_t2r_trans = NULL; + free(prev_t2r_raw); + prev_t2r_raw = NULL; + if (trans_to_raw_context(trans, rawp)) + *rawp = strdup(trans); + if (*rawp) { + prev_t2r_trans = strdup(trans); + if (!prev_t2r_trans) + goto out; + prev_t2r_raw = strdup(*rawp); + if (!prev_t2r_raw) { + free(prev_t2r_trans); + prev_t2r_trans = NULL; + } + } + } + out: + return *rawp ? 0 : -1; +} + +hidden_def(selinux_trans_to_raw_context) + +int selinux_raw_to_trans_context(const char * raw, + char ** transp) +{ + if (!raw) { + *transp = NULL; + return 0; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *transp = strdup(raw); + goto out; + } + + if (prev_r2t_raw && strcmp(prev_r2t_raw, raw) == 0) { + *transp = strdup(prev_r2t_trans); + } else { + free(prev_r2t_raw); + prev_r2t_raw = NULL; + free(prev_r2t_trans); + prev_r2t_trans = NULL; + if (raw_to_trans_context(raw, transp)) + *transp = strdup(raw); + if (*transp) { + prev_r2t_raw = strdup(raw); + if (!prev_r2t_raw) + goto out; + prev_r2t_trans = strdup(*transp); + if (!prev_r2t_trans) { + free(prev_r2t_raw); + prev_r2t_raw = NULL; + } + } + } + out: + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_to_trans_context) + +int selinux_raw_context_to_color(const char * raw, char **transp) +{ + if (!raw) { + *transp = NULL; + return -1; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *transp = strdup(raw); + goto out; + } + + if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) { + *transp = strdup(prev_r2c_trans); + } else { + free(prev_r2c_raw); + prev_r2c_raw = NULL; + free(prev_r2c_trans); + prev_r2c_trans = NULL; + if (raw_context_to_color(raw, transp)) + return -1; + if (*transp) { + prev_r2c_raw = strdup(raw); + if (!prev_r2c_raw) + goto out; + prev_r2c_trans = strdup(*transp); + if (!prev_r2c_trans) { + free(prev_r2c_raw); + prev_r2c_raw = NULL; + } + } + } + out: + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_context_to_color) +#else /*DISABLE_SETRANS*/ + +int selinux_trans_to_raw_context(const char * trans, + char ** rawp) +{ + if (!trans) { + *rawp = NULL; + return 0; + } + + *rawp = strdup(trans); + + return *rawp ? 0 : -1; +} + +hidden_def(selinux_trans_to_raw_context) + +int selinux_raw_to_trans_context(const char * raw, + char ** transp) +{ + if (!raw) { + *transp = NULL; + return 0; + } + *transp = strdup(raw); + + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_to_trans_context) +#endif /*DISABLE_SETRANS*/
diff --git a/selinux/libselinux/src/setrans_internal.h b/selinux/libselinux/src/setrans_internal.h new file mode 100644 index 0000000..b3bdca2 --- /dev/null +++ b/selinux/libselinux/src/setrans_internal.h
@@ -0,0 +1,10 @@ +/* Author: Trusted Computer Solutions, Inc. */ +#include <selinux/selinux.h> + +#define SETRANS_UNIX_SOCKET SELINUX_TRANS_DIR "/.setrans-unix" + +#define RAW_TO_TRANS_CONTEXT 2 +#define TRANS_TO_RAW_CONTEXT 3 +#define RAW_CONTEXT_TO_COLOR 4 +#define MAX_DATA_BUF 8192 +
diff --git a/selinux/libselinux/src/seusers.c b/selinux/libselinux/src/seusers.c new file mode 100644 index 0000000..09e704b --- /dev/null +++ b/selinux/libselinux/src/seusers.c
@@ -0,0 +1,331 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <ctype.h> +#include <errno.h> +#include <selinux/selinux.h> +#include <selinux/context.h> +#include "selinux_internal.h" + +/* Process line from seusers.conf and split into its fields. + Returns 0 on success, -1 on comments, and -2 on error. */ +static int process_seusers(const char *buffer, + char **luserp, + char **seuserp, char **levelp, int mls_enabled) +{ + char *newbuf = strdup(buffer); + char *luser = NULL, *seuser = NULL, *level = NULL; + char *start, *end; + int mls_found = 1; + + if (!newbuf) + goto err; + + start = newbuf; + while (isspace(*start)) + start++; + if (*start == '#' || *start == 0) { + free(newbuf); + return -1; /* Comment or empty line, skip over */ + } + end = strchr(start, ':'); + if (!end) + goto err; + *end = 0; + + luser = strdup(start); + if (!luser) + goto err; + + start = end + 1; + end = strchr(start, ':'); + if (!end) { + mls_found = 0; + + end = start; + while (*end && !isspace(*end)) + end++; + } + *end = 0; + + seuser = strdup(start); + if (!seuser) + goto err; + + if (!strcmp(seuser, "")) + goto err; + + /* Skip MLS if disabled, or missing. */ + if (!mls_enabled || !mls_found) + goto out; + + start = ++end; + while (*end && !isspace(*end)) + end++; + *end = 0; + + level = strdup(start); + if (!level) + goto err; + + if (!strcmp(level, "")) + goto err; + + out: + free(newbuf); + *luserp = luser; + *seuserp = seuser; + *levelp = level; + return 0; + err: + free(newbuf); + free(luser); + free(seuser); + free(level); + return -2; /* error */ +} + +int require_seusers hidden = 0; + +#include <pwd.h> +#include <grp.h> + +static gid_t get_default_gid(const char *name) { + struct passwd pwstorage, *pwent = NULL; + gid_t gid = -1; + /* Allocate space for the getpwnam_r buffer */ + long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen <= 0) return -1; + char *rbuf = malloc(rbuflen); + if (rbuf == NULL) return -1; + + int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (retval == 0 && pwent) { + gid = pwent->pw_gid; + } + free(rbuf); + return gid; +} + +static int check_group(const char *group, const char *name, const gid_t gid) { + int match = 0; + int i, ng = 0; + gid_t *groups = NULL; + struct group gbuf, *grent = NULL; + + long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (rbuflen <= 0) + return 0; + char *rbuf; + + while(1) { + rbuf = malloc(rbuflen); + if (rbuf == NULL) + return 0; + int retval = getgrnam_r(group, &gbuf, rbuf, + rbuflen, &grent); + if ( retval == ERANGE ) + { + free(rbuf); + rbuflen = rbuflen * 2; + } else if ( retval != 0 || grent == NULL ) + { + goto done; + } else + { + break; + } + } + + if (getgrouplist(name, gid, NULL, &ng) < 0) { + if (ng == 0) + goto done; + groups = calloc(ng, sizeof(*groups)); + if (!groups) + goto done; + if (getgrouplist(name, gid, groups, &ng) < 0) + goto done; + } else { + /* WTF? ng was 0 and we didn't fail? Are we in 0 groups? */ + goto done; + } + + for (i = 0; i < ng; i++) { + if (grent->gr_gid == groups[i]) { + match = 1; + goto done; + } + } + + done: + free(groups); + free(rbuf); + return match; +} + +int getseuserbyname(const char *name, char **r_seuser, char **r_level) +{ + FILE *cfg = NULL; + size_t size = 0; + char *buffer = NULL; + int rc; + unsigned long lineno = 0; + int mls_enabled = is_selinux_mls_enabled(); + + char *username = NULL; + char *seuser = NULL; + char *level = NULL; + char *groupseuser = NULL; + char *grouplevel = NULL; + char *defaultseuser = NULL; + char *defaultlevel = NULL; + + gid_t gid = get_default_gid(name); + + cfg = fopen(selinux_usersconf_path(), "r"); + if (!cfg) + goto nomatch; + + __fsetlocking(cfg, FSETLOCKING_BYCALLER); + while (getline(&buffer, &size, cfg) > 0) { + ++lineno; + rc = process_seusers(buffer, &username, &seuser, &level, + mls_enabled); + if (rc == -1) + continue; /* comment, skip */ + if (rc == -2) { + fprintf(stderr, "%s: error on line %lu, skipping...\n", + selinux_usersconf_path(), lineno); + continue; + } + + if (!strcmp(username, name)) + break; + + if (username[0] == '%' && + !groupseuser && + check_group(&username[1], name, gid)) { + groupseuser = seuser; + grouplevel = level; + } else { + if (!defaultseuser && + !strcmp(username, "__default__")) { + defaultseuser = seuser; + defaultlevel = level; + } else { + free(seuser); + free(level); + } + } + free(username); + username = NULL; + seuser = NULL; + } + + free(buffer); + fclose(cfg); + + if (seuser) { + free(username); + free(defaultseuser); + free(defaultlevel); + free(groupseuser); + free(grouplevel); + *r_seuser = seuser; + *r_level = level; + return 0; + } + + if (groupseuser) { + free(defaultseuser); + free(defaultlevel); + *r_seuser = groupseuser; + *r_level = grouplevel; + return 0; + } + + if (defaultseuser) { + *r_seuser = defaultseuser; + *r_level = defaultlevel; + return 0; + } + + nomatch: + if (require_seusers) + return -1; + + /* Fall back to the Linux username and no level. */ + *r_seuser = strdup(name); + if (!(*r_seuser)) + return -1; + *r_level = NULL; + return 0; +} + +int getseuser(const char *username, const char *service, + char **r_seuser, char **r_level) { + int ret = -1; + int len = 0; + char *seuser = NULL; + char *level = NULL; + char *buffer = NULL; + size_t size = 0; + char *rec = NULL; + char *path=NULL; + FILE *fp = NULL; + if (asprintf(&path,"%s/logins/%s", selinux_policy_root(), username) < 0) + goto err; + fp = fopen(path, "r"); + free(path); + if (fp == NULL) goto err; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while (getline(&buffer, &size, fp) > 0) { + if (strncmp(buffer, "*:", 2) == 0) { + free(rec); + rec = strdup(buffer); + continue; + } + if (!service) + continue; + len = strlen(service); + if ((strncmp(buffer, service, len) == 0) && + (buffer[len] == ':')) { + free(rec); + rec = strdup(buffer); + break; + } + } + + if (! rec) goto err; + seuser = strchr(rec, ':'); + if (! seuser) goto err; + + seuser++; + level = strchr(seuser, ':'); + if (! level) goto err; + *level = 0; + level++; + *r_seuser = strdup(seuser); + if (! *r_seuser) goto err; + + len = strlen(level); + if (len && level[len-1] == '\n') + level[len-1] = 0; + + *r_level = strdup(level); + if (! *r_level) { + free(*r_seuser); + goto err; + } + ret = 0; + + err: + free(buffer); + if (fp) fclose(fp); + free(rec); + + return (ret ? getseuserbyname(username, r_seuser, r_level) : ret); +}
diff --git a/selinux/libselinux/src/sha1.c b/selinux/libselinux/src/sha1.c new file mode 100644 index 0000000..5f02af8 --- /dev/null +++ b/selinux/libselinux/src/sha1.c
@@ -0,0 +1,214 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// LibSha1 +// +// Implementation of SHA1 hash function. +// Original author: Steve Reid <sreid@sea-to-sky.net> +// Contributions by: James H. Brown <jbrown@burgoyne.com>, Saul Kravitz <Saul.Kravitz@celera.com>, +// and Ralph Giles <giles@ghostscript.com> +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +// Modified to stop symbols being exported for libselinux shared library - October 2015 +// Richard Haines <richard_c_haines@btinternet.com> +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "sha1.h" +#include "dso.h" +#include <memory.h> + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union +{ + uint8_t c [64]; + uint32_t l [16]; +} CHAR64LONG16; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +// blk0() and blk() perform the initial expand. +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) + +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +// (R0+R1), R2, R3, R4 are the different operations used in SHA1 +#define R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk0(i)+ 0x5A827999 + rol(v,5); w=rol(w,30); +#define R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk(i) + 0x5A827999 + rol(v,5); w=rol(w,30); +#define R2(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0x6ED9EBA1 + rol(v,5); w=rol(w,30); +#define R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + blk(i) + 0x8F1BBCDC + rol(v,5); w=rol(w,30); +#define R4(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0xCA62C1D6 + rol(v,5); w=rol(w,30); + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TransformFunction +// +// Hash a single 512-bit block. This is the core of the algorithm +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static +void + TransformFunction + ( + uint32_t state[5], + const uint8_t buffer[64] + ) +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t e; + uint8_t workspace[64]; + CHAR64LONG16* block = (CHAR64LONG16*) workspace; + + memcpy( block, buffer, 64 ); + + // Copy context->state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + // Add the working vars back into context.state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Initialise +// +// Initialises an SHA1 Context. Use this to initialise/reset a context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Initialise + ( + Sha1Context* Context + ) +{ + // SHA1 initialization constants + Context->State[0] = 0x67452301; + Context->State[1] = 0xEFCDAB89; + Context->State[2] = 0x98BADCFE; + Context->State[3] = 0x10325476; + Context->State[4] = 0xC3D2E1F0; + Context->Count[0] = 0; + Context->Count[1] = 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Update +// +// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Update + ( + Sha1Context* Context, + void* Buffer, + uint32_t BufferSize + ) +{ + uint32_t i; + uint32_t j; + + j = (Context->Count[0] >> 3) & 63; + if( (Context->Count[0] += BufferSize << 3) < (BufferSize << 3) ) + { + Context->Count[1]++; + } + + Context->Count[1] += (BufferSize >> 29); + if( (j + BufferSize) > 63 ) + { + i = 64 - j; + memcpy( &Context->Buffer[j], Buffer, i ); + TransformFunction(Context->State, Context->Buffer); + for( ; i + 63 < BufferSize; i += 64 ) + { + TransformFunction(Context->State, (uint8_t*)Buffer + i); + } + j = 0; + } + else + { + i = 0; + } + + memcpy( &Context->Buffer[j], &((uint8_t*)Buffer)[i], BufferSize - i ); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Finalise +// +// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After +// calling this, Sha1Initialised must be used to reuse the context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Finalise + ( + Sha1Context* Context, + SHA1_HASH* Digest + ) +{ + uint32_t i; + uint8_t finalcount[8]; + + for( i=0; i<8; i++ ) + { + finalcount[i] = (unsigned char)((Context->Count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); // Endian independent + } + Sha1Update( Context, (uint8_t*)"\x80", 1 ); + while( (Context->Count[0] & 504) != 448 ) + { + Sha1Update( Context, (uint8_t*)"\0", 1 ); + } + + Sha1Update( Context, finalcount, 8 ); // Should cause a Sha1TransformFunction() + for( i=0; i<SHA1_HASH_SIZE; i++ ) + { + Digest->bytes[i] = (uint8_t)((Context->State[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +}
diff --git a/selinux/libselinux/src/sha1.h b/selinux/libselinux/src/sha1.h new file mode 100644 index 0000000..eac3c19 --- /dev/null +++ b/selinux/libselinux/src/sha1.h
@@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// LibSha1 +// +// Implementation of SHA1 hash function. +// Original author: Steve Reid <sreid@sea-to-sky.net> +// Contributions by: James H. Brown <jbrown@burgoyne.com>, Saul Kravitz <Saul.Kravitz@celera.com>, +// and Ralph Giles <giles@ghostscript.com> +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef _sha1_h_ +#define _sha1_h_ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include <stdint.h> +#include <stdio.h> + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Sha1Context - This must be initialised using Sha1Initialised. Do not modify the contents of this structure directly. +typedef struct +{ + uint32_t State[5]; + uint32_t Count[2]; + uint8_t Buffer[64]; +} Sha1Context; + +#define SHA1_HASH_SIZE ( 160 / 8 ) + +typedef struct +{ + uint8_t bytes [SHA1_HASH_SIZE]; +} SHA1_HASH; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Initialise +// +// Initialises an SHA1 Context. Use this to initialise/reset a context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Initialise + ( + Sha1Context* Context + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Update +// +// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Update + ( + Sha1Context* Context, + void* Buffer, + uint32_t BufferSize + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Finalise +// +// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After +// calling this, Sha1Initialised must be used to reuse the context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Finalise + ( + Sha1Context* Context, + SHA1_HASH* Digest + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif //_sha1_h_
diff --git a/selinux/libselinux/src/stringrep.c b/selinux/libselinux/src/stringrep.c new file mode 100644 index 0000000..2dbec2b --- /dev/null +++ b/selinux/libselinux/src/stringrep.c
@@ -0,0 +1,349 @@ +/* + * String representation support for classes and permissions. + */ +#include <sys/stat.h> +#include <dirent.h> +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <ctype.h> +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +#define MAXVECTORS 8*sizeof(access_vector_t) + +struct discover_class_node { + char *name; + security_class_t value; + char **perms; + + struct discover_class_node *next; +}; + +static struct discover_class_node *discover_class_cache = NULL; + +static struct discover_class_node * get_class_cache_entry_name(const char *s) +{ + struct discover_class_node *node = discover_class_cache; + + for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); + + return node; +} + +static struct discover_class_node * get_class_cache_entry_value(security_class_t c) +{ + struct discover_class_node *node = discover_class_cache; + + for (; node != NULL && c != node->value; node = node->next); + + return node; +} + +static struct discover_class_node * discover_class(const char *s) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + DIR *dir; + struct dirent *dentry; + size_t i; + + struct discover_class_node *node; + + if (!selinux_mnt) { + errno = ENOENT; + return NULL; + } + + /* allocate a node */ + node = malloc(sizeof(struct discover_class_node)); + if (node == NULL) + return NULL; + + /* allocate array for perms */ + node->perms = calloc(MAXVECTORS,sizeof(char*)); + if (node->perms == NULL) + goto err1; + + /* load up the name */ + node->name = strdup(s); + if (node->name == NULL) + goto err2; + + /* load up class index */ + snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); + fd = open(path, O_RDONLY); + if (fd < 0) + goto err3; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + goto err3; + + if (sscanf(buf, "%hu", &node->value) != 1) + goto err3; + + /* load up permission indicies */ + snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); + dir = opendir(path); + if (dir == NULL) + goto err3; + + dentry = readdir(dir); + while (dentry != NULL) { + unsigned int value; + struct stat m; + + snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto err4; + + if (fstat(fd, &m) < 0) { + close(fd); + goto err4; + } + + if (m.st_mode & S_IFDIR) { + close(fd); + dentry = readdir(dir); + continue; + } + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + goto err4; + + if (sscanf(buf, "%u", &value) != 1) + goto err4; + + if (value == 0 || value > MAXVECTORS) + goto err4; + + node->perms[value-1] = strdup(dentry->d_name); + if (node->perms[value-1] == NULL) + goto err4; + + dentry = readdir(dir); + } + closedir(dir); + + node->next = discover_class_cache; + discover_class_cache = node; + + return node; + +err4: + closedir(dir); + for (i=0; i<MAXVECTORS; i++) + free(node->perms[i]); +err3: + free(node->name); +err2: + free(node->perms); +err1: + free(node); + return NULL; +} + +hidden void flush_class_cache(void) +{ + struct discover_class_node *cur = discover_class_cache, *prev = NULL; + size_t i; + + while (cur != NULL) { + free(cur->name); + + for (i = 0; i < MAXVECTORS; i++) + free(cur->perms[i]); + + free(cur->perms); + + prev = cur; + cur = cur->next; + + free(prev); + } + + discover_class_cache = NULL; +} + +security_class_t string_to_security_class(const char *s) +{ + struct discover_class_node *node; + + node = get_class_cache_entry_name(s); + if (node == NULL) { + node = discover_class(s); + + if (node == NULL) { + errno = EINVAL; + return 0; + } + } + + return map_class(node->value); +} + +security_class_t mode_to_security_class(mode_t m) { + + if (S_ISREG(m)) + return string_to_security_class("file"); + if (S_ISDIR(m)) + return string_to_security_class("dir"); + if (S_ISCHR(m)) + return string_to_security_class("chr_file"); + if (S_ISBLK(m)) + return string_to_security_class("blk_file"); + if (S_ISFIFO(m)) + return string_to_security_class("fifo_file"); + if (S_ISLNK(m)) + return string_to_security_class("lnk_file"); + if (S_ISSOCK(m)) + return string_to_security_class("sock_file"); + + errno=EINVAL; + return 0; +} + +access_vector_t string_to_av_perm(security_class_t tclass, const char *s) +{ + struct discover_class_node *node; + security_class_t kclass = unmap_class(tclass); + + node = get_class_cache_entry_value(kclass); + if (node != NULL) { + size_t i; + for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++) + if (strcmp(node->perms[i],s) == 0) + return map_perm(tclass, 1<<i); + } + + errno = EINVAL; + return 0; +} + +const char *security_class_to_string(security_class_t tclass) +{ + struct discover_class_node *node; + + tclass = unmap_class(tclass); + + node = get_class_cache_entry_value(tclass); + if (node == NULL) + return NULL; + else + return node->name; +} + +const char *security_av_perm_to_string(security_class_t tclass, + access_vector_t av) +{ + struct discover_class_node *node; + size_t i; + + av = unmap_perm(tclass, av); + tclass = unmap_class(tclass); + + node = get_class_cache_entry_value(tclass); + if (av && node) + for (i = 0; i<MAXVECTORS; i++) + if ((1<<i) & av) + return node->perms[i]; + + return NULL; +} + +int security_av_string(security_class_t tclass, access_vector_t av, char **res) +{ + unsigned int i = 0; + size_t len = 5; + access_vector_t tmp = av; + int rc = 0; + const char *str; + char *ptr; + + /* first pass computes the required length */ + while (tmp) { + if (tmp & 1) { + str = security_av_perm_to_string(tclass, av & (1<<i)); + if (str) + len += strlen(str) + 1; + else { + rc = -1; + errno = EINVAL; + goto out; + } + } + tmp >>= 1; + i++; + } + + *res = malloc(len); + if (!*res) { + rc = -1; + goto out; + } + + /* second pass constructs the string */ + i = 0; + tmp = av; + ptr = *res; + + if (!av) { + sprintf(ptr, "null"); + goto out; + } + + ptr += sprintf(ptr, "{ "); + while (tmp) { + if (tmp & 1) + ptr += sprintf(ptr, "%s ", security_av_perm_to_string( + tclass, av & (1<<i))); + tmp >>= 1; + i++; + } + sprintf(ptr, "}"); +out: + return rc; +} + +void print_access_vector(security_class_t tclass, access_vector_t av) +{ + const char *permstr; + access_vector_t bit = 1; + + if (av == 0) { + printf(" null"); + return; + } + + printf(" {"); + + while (av) { + if (av & bit) { + permstr = security_av_perm_to_string(tclass, bit); + if (!permstr) + break; + printf(" %s", permstr); + av &= ~bit; + } + bit <<= 1; + } + + if (av) + printf(" 0x%x", av); + printf(" }"); +}
diff --git a/selinux/libselinux/utils/Makefile b/selinux/libselinux/utils/Makefile new file mode 100644 index 0000000..cf7af52 --- /dev/null +++ b/selinux/libselinux/utils/Makefile
@@ -0,0 +1,58 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +LIBDIR ?= $(PREFIX)/lib +USRBINDIR ?= $(PREFIX)/sbin +SBINDIR ?= $(DESTDIR)/sbin + +MAX_STACK_SIZE=8192 +CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissing-include-dirs \ + -Wunused -Wunknown-pragmas -Wstrict-aliasing -Wshadow -Wpointer-arith \ + -Wbad-function-cast -Wcast-align -Wwrite-strings -Wlogical-op -Waggregate-return \ + -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes \ + -Wmissing-declarations -Wmissing-noreturn -Wmissing-format-attribute \ + -Wredundant-decls -Wnested-externs -Winline -Winvalid-pch -Wvolatile-register-var \ + -Wdisabled-optimization -Wbuiltin-macro-redefined -Wpacked-bitfield-compat \ + -Wsync-nand -Wattributes -Wcoverage-mismatch -Wmultichar -Wcpp \ + -Wdeprecated-declarations -Wdiv-by-zero -Wdouble-promotion -Wendif-labels -Wextra \ + -Wformat-contains-nul -Wformat-extra-args -Wformat-zero-length -Wformat=2 -Wmultichar \ + -Wnormalized=nfc -Woverflow -Wpointer-to-int-cast -Wpragmas -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines \ + -Wno-missing-field-initializers -Wno-sign-compare -Wjump-misses-init \ + -Wno-format-nonliteral -Wframe-larger-than=$(MAX_STACK_SIZE) -Wp,-D_FORTIFY_SOURCE=2 \ + -fstack-protector-all --param=ssp-buffer-size=4 -fexceptions \ + -fasynchronous-unwind-tables -fdiagnostics-show-option -funit-at-a-time \ + -fipa-pure-const -Wno-suggest-attribute=pure -Wno-suggest-attribute=const \ + -Werror -Wno-aggregate-return -Wno-redundant-decls +override CFLAGS += -I../include -D_GNU_SOURCE $(EMFLAGS) +LDLIBS += -L../src -lselinux -L$(LIBDIR) + +TARGETS=$(patsubst %.c,%,$(wildcard *.c)) + +sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a -lsepol + +selinux_restorecon: LDLIBS += -lsepol + +ifeq ($(DISABLE_AVC),y) + UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel +endif +ifeq ($(DISABLE_BOOL),y) + UNUSED_TARGETS+=getsebool togglesebool +endif +TARGETS:= $(filter-out $(UNUSED_TARGETS), $(TARGETS)) + +all: $(TARGETS) + +install: all + -mkdir -p $(USRBINDIR) + install -m 755 $(TARGETS) $(USRBINDIR) + -mkdir -p $(SBINDIR) +clean: + rm -f $(TARGETS) *.o *~ + +distclean: clean + +indent: + ../../scripts/Lindent $(wildcard *.[ch]) + +relabel: +
diff --git a/selinux/libselinux/utils/avcstat.c b/selinux/libselinux/utils/avcstat.c new file mode 100644 index 0000000..1d4d5c8 --- /dev/null +++ b/selinux/libselinux/utils/avcstat.c
@@ -0,0 +1,235 @@ +/* + * avcstat - Display SELinux avc statistics. + * + * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <libgen.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <linux/limits.h> + +#define DEF_STAT_FILE "/avc/cache_stats" +#define DEF_BUF_SIZE 8192 +#define HEADERS "lookups hits misses allocations reclaims frees" + +struct avc_cache_stats { + unsigned long long lookups; + unsigned long long hits; + unsigned long long misses; + unsigned long long allocations; + unsigned long long reclaims; + unsigned long long frees; +}; + +static int interval; +static int rows; +static char *progname; +static char buf[DEF_BUF_SIZE]; + +/* selinuxfs mount point */ +extern char *selinux_mnt; + +static __attribute__((__format__(printf,1,2))) void die(const char *msg, ...) +{ + va_list args; + + fputs("ERROR: ", stderr); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + + fputc('\n', stderr); + exit(1); +} + +static void usage(void) +{ + printf("\nUsage: %s [-c] [-f status_file] [interval]\n\n", progname); + printf + ("Display SELinux AVC statistics. If the interval parameter is specified, the\n"); + printf + ("program will loop, displaying updated statistics every \'interval\' seconds.\n"); + printf + ("Relative values are displayed by default. Use the -c option to specify the\n"); + printf + ("display of cumulative values. The -f option specifies the location of the\n"); + printf("AVC statistics file, defaulting to \'%s%s\'.\n\n", selinux_mnt, + DEF_STAT_FILE); +} + +static void set_window_rows(void) +{ + int ret; + struct winsize ws; + + ret = ioctl(fileno(stdout), TIOCGWINSZ, &ws); + if (ret < 0 || ws.ws_row < 3) + ws.ws_row = 24; + rows = ws.ws_row; +} + +static void sighandler(int num) +{ + if (num == SIGWINCH) + set_window_rows(); +} + +int main(int argc, char **argv) +{ + struct avc_cache_stats tot, rel, last; + int fd, i, cumulative = 0; + struct sigaction sa; + char avcstatfile[PATH_MAX]; + snprintf(avcstatfile, sizeof avcstatfile, "%s%s", selinux_mnt, + DEF_STAT_FILE); + progname = basename(argv[0]); + + memset(&last, 0, sizeof(last)); + + while ((i = getopt(argc, argv, "cf:h?-")) != -1) { + switch (i) { + case 'c': + cumulative = 1; + break; + case 'f': + strncpy(avcstatfile, optarg, sizeof avcstatfile); + break; + case 'h': + case '-': + usage(); + exit(0); + default: + usage(); + die("unrecognized parameter '%c'", i); + } + } + + if (optind < argc) { + char *arg = argv[optind]; + unsigned int n = strtoul(arg, NULL, 10); + + if (errno == ERANGE) { + usage(); + die("invalid interval \'%s\'", arg); + } + if (n == 0) { + usage(); + exit(0); + } + interval = n; + } + + sa.sa_handler = sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + + i = sigaction(SIGWINCH, &sa, NULL); + if (i < 0) + die("sigaction"); + + set_window_rows(); + fd = open(avcstatfile, O_RDONLY); + if (fd < 0) + die("open: \'%s\'", avcstatfile); + + for (i = 0;; i++) { + char *line; + ssize_t ret, parsed = 0; + + memset(buf, 0, DEF_BUF_SIZE); + ret = read(fd, buf, DEF_BUF_SIZE-1); + if (ret < 0) + die("read"); + + if (ret == 0) + die("read: \'%s\': unexpected end of file", + avcstatfile); + + line = strtok(buf, "\n"); + if (!line) + die("unable to parse \'%s\': end of line not found", + avcstatfile); + + if (strcmp(line, HEADERS)) + die("unable to parse \'%s\': invalid headers", + avcstatfile); + + if (!i || !(i % (rows - 2))) + printf("%10s %10s %10s %10s %10s %10s\n", "lookups", + "hits", "misses", "allocs", "reclaims", "frees"); + + memset(&tot, 0, sizeof(tot)); + + while ((line = strtok(NULL, "\n"))) { + struct avc_cache_stats tmp; + + ret = sscanf(line, "%llu %llu %llu %llu %llu %llu", + &tmp.lookups, + &tmp.hits, + &tmp.misses, + &tmp.allocations, + &tmp.reclaims, &tmp.frees); + if (ret != 6) + die("unable to parse \'%s\': scan error", + avcstatfile); + + tot.lookups += tmp.lookups; + tot.hits += tmp.hits; + tot.misses += tmp.misses; + tot.allocations += tmp.allocations; + tot.reclaims += tmp.reclaims; + tot.frees += tmp.frees; + parsed = 1; + } + + if (!parsed) + die("unable to parse \'%s\': no data", avcstatfile); + + if (cumulative || (!cumulative && !i)) + printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", + tot.lookups, tot.hits, tot.misses, + tot.allocations, tot.reclaims, tot.frees); + else { + rel.lookups = tot.lookups - last.lookups; + rel.hits = tot.hits - last.hits; + rel.misses = tot.misses - last.misses; + rel.allocations = tot.allocations - last.allocations; + rel.reclaims = tot.reclaims - last.reclaims; + rel.frees = tot.frees - last.frees; + printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", + rel.lookups, rel.hits, rel.misses, + rel.allocations, rel.reclaims, rel.frees); + } + + if (!interval) + break; + + memcpy(&last, &tot, sizeof(last)); + sleep(interval); + + ret = lseek(fd, 0, 0); + if (ret < 0) + die("lseek"); + } + + close(fd); + return 0; +}
diff --git a/selinux/libselinux/utils/compute_av.c b/selinux/libselinux/utils/compute_av.c new file mode 100644 index 0000000..574fa6e --- /dev/null +++ b/selinux/libselinux/utils/compute_av.c
@@ -0,0 +1,55 @@ +#include <unistd.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + struct av_decision avd; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); + exit(2); + } + + ret = security_compute_av(argv[1], argv[2], tclass, 1, &avd); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_av failed\n", argv[0]); + exit(3); + } + + printf("allowed="); + print_access_vector(tclass, avd.allowed); + printf("\n"); + + if (avd.decided != ~0U) { + printf("decided="); + print_access_vector(tclass, avd.decided); + printf("\n"); + } + + if (avd.auditallow) { + printf("auditallow="); + print_access_vector(tclass, avd.auditallow); + printf("\n"); + } + + if (avd.auditdeny != ~0U) { + printf("auditdeny"); + print_access_vector(tclass, avd.auditdeny); + printf("\n"); + } + + exit(0); +}
diff --git a/selinux/libselinux/utils/compute_create.c b/selinux/libselinux/utils/compute_create.c new file mode 100644 index 0000000..4abc29f --- /dev/null +++ b/selinux/libselinux/utils/compute_create.c
@@ -0,0 +1,36 @@ +#include <unistd.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "Invalid class '%s'\n", argv[3]); + exit(2); + } + + ret = security_compute_create(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_create failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +}
diff --git a/selinux/libselinux/utils/compute_member.c b/selinux/libselinux/utils/compute_member.c new file mode 100644 index 0000000..14edd45 --- /dev/null +++ b/selinux/libselinux/utils/compute_member.c
@@ -0,0 +1,36 @@ +#include <unistd.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "Invalid class '%s'\n", argv[3]); + exit(2); + } + + ret = security_compute_member(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_member failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +}
diff --git a/selinux/libselinux/utils/compute_relabel.c b/selinux/libselinux/utils/compute_relabel.c new file mode 100644 index 0000000..970750e --- /dev/null +++ b/selinux/libselinux/utils/compute_relabel.c
@@ -0,0 +1,36 @@ +#include <unistd.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); + exit(2); + } + + ret = security_compute_relabel(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_relabel failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +}
diff --git a/selinux/libselinux/utils/compute_user.c b/selinux/libselinux/utils/compute_user.c new file mode 100644 index 0000000..cae62b2 --- /dev/null +++ b/selinux/libselinux/utils/compute_user.c
@@ -0,0 +1,38 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + char **buf, **ptr; + int ret; + + if (argc != 3) { + fprintf(stderr, "usage: %s context user\n", argv[0]); + exit(1); + } + + ret = security_compute_user(argv[1], argv[2], &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_user(%s,%s) failed\n", + argv[0], argv[1], argv[2]); + exit(2); + } + + if (!buf[0]) { + printf("none\n"); + exit(0); + } + + for (ptr = buf; *ptr; ptr++) { + printf("%s\n", *ptr); + } + freeconary(buf); + exit(0); +}
diff --git a/selinux/libselinux/utils/getconlist.c b/selinux/libselinux/utils/getconlist.c new file mode 100644 index 0000000..872ce05 --- /dev/null +++ b/selinux/libselinux/utils/getconlist.c
@@ -0,0 +1,73 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <selinux/selinux.h> +#include <selinux/get_context_list.h> + +static void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s [-l level] user [context]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +int main(int argc, char **argv) +{ + char **list, *usercon = NULL, *cur_context = NULL; + char *user = NULL, *level = NULL; + int ret, i, opt; + + while ((opt = getopt(argc, argv, "l:")) > 0) { + switch (opt) { + case 'l': + level = strdup(optarg); + break; + default: + usage(argv[0], "invalid option", 1); + } + } + + if (((argc - optind) < 1) || ((argc - optind) > 2)) + usage(argv[0], "invalid number of arguments", 2); + + /* If selinux isn't available, bail out. */ + if (!is_selinux_enabled()) { + fprintf(stderr, + "getconlist may be used only on a SELinux kernel.\n"); + return 1; + } + + user = argv[optind]; + + /* If a context wasn't passed, use the current context. */ + if (((argc - optind) < 2)) { + if (getcon(&cur_context) < 0) { + fprintf(stderr, "Couldn't get current context.\n"); + return 2; + } + } else + cur_context = argv[optind + 1]; + + /* Get the list and print it */ + if (level) + ret = + get_ordered_context_list_with_level(user, level, + cur_context, &list); + else + ret = get_ordered_context_list(user, cur_context, &list); + if (ret != -1) { + for (i = 0; list[i]; i++) + puts(list[i]); + freeconary(list); + } + + free(usercon); + + return 0; +}
diff --git a/selinux/libselinux/utils/getdefaultcon.c b/selinux/libselinux/utils/getdefaultcon.c new file mode 100644 index 0000000..c6f7151 --- /dev/null +++ b/selinux/libselinux/utils/getdefaultcon.c
@@ -0,0 +1,92 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <selinux/selinux.h> +#include <selinux/get_context_list.h> + +static void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s [-l level] [-s service] user [fromcon]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +int main(int argc, char **argv) +{ + char * usercon = NULL, *cur_context = NULL; + char *user = NULL, *level = NULL, *role=NULL, *seuser=NULL, *dlevel=NULL; + char *service = NULL; + int ret, opt; + int verbose = 0; + + while ((opt = getopt(argc, argv, "l:r:s:v")) > 0) { + switch (opt) { + case 'l': + level = strdup(optarg); + break; + case 'r': + role = strdup(optarg); + break; + case 's': + service = strdup(optarg); + break; + case 'v': + verbose = 1; + break; + default: + usage(argv[0], "invalid option", 1); + } + } + + if (((argc - optind) < 1) || ((argc - optind) > 2)) + usage(argv[0], "invalid number of arguments", 2); + + /* If selinux isn't available, bail out. */ + if (!is_selinux_enabled()) { + fprintf(stderr, + "%s may be used only on a SELinux kernel.\n", argv[0]); + return 1; + } + + user = argv[optind]; + + /* If a context wasn't passed, use the current context. */ + if (((argc - optind) < 2)) { + if (getcon(&cur_context) < 0) { + fprintf(stderr, "Couldn't get current context.\n"); + return 2; + } + } else + cur_context = argv[optind + 1]; + + if ((ret = getseuser(user, service, &seuser, &dlevel)) == 0) { + if (! level) level=dlevel; + if (role != NULL && role[0]) + ret=get_default_context_with_rolelevel(seuser, role, level,cur_context,&usercon); + else + ret=get_default_context_with_level(seuser, level, cur_context,&usercon); + } + if (ret < 0) + perror(argv[0]); + else { + if (verbose) { + printf("%s: %s from %s %s %s %s -> %s\n", argv[0], user, cur_context, seuser, role, level, usercon); + } else { + printf("%s\n", usercon); + } + } + + free(role); + free(seuser); + if (level != dlevel) free(level); + free(dlevel); + free(usercon); + + return ret >= 0; +}
diff --git a/selinux/libselinux/utils/getenforce.c b/selinux/libselinux/utils/getenforce.c new file mode 100644 index 0000000..e5d19c5 --- /dev/null +++ b/selinux/libselinux/utils/getenforce.c
@@ -0,0 +1,32 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused))) +{ + int rc; + + rc = is_selinux_enabled(); + if (rc < 0) { + fputs("getenforce: is_selinux_enabled() failed", stderr); + return 2; + } + if (rc == 1) { + rc = security_getenforce(); + if (rc < 0) { + fputs("getenforce: getenforce() failed", stderr); + return 2; + } + + if (rc) + puts("Enforcing"); + else + puts("Permissive"); + } else { + puts("Disabled"); + } + + return 0; +}
diff --git a/selinux/libselinux/utils/getfilecon.c b/selinux/libselinux/utils/getfilecon.c new file mode 100644 index 0000000..a7a51ab --- /dev/null +++ b/selinux/libselinux/utils/getfilecon.c
@@ -0,0 +1,27 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + char *buf; + int rc, i; + + if (argc < 2) { + fprintf(stderr, "usage: %s path...\n", argv[0]); + exit(1); + } + + for (i = 1; i < argc; i++) { + rc = getfilecon(argv[i], &buf); + if (rc < 0) { + fprintf(stderr, "%s: getfilecon(%s) failed\n", argv[0], + argv[i]); + exit(2); + } + printf("%s\t%s\n", argv[i], buf); + freecon(buf); + } + exit(0); +}
diff --git a/selinux/libselinux/utils/getpidcon.c b/selinux/libselinux/utils/getpidcon.c new file mode 100644 index 0000000..3df0da1 --- /dev/null +++ b/selinux/libselinux/utils/getpidcon.c
@@ -0,0 +1,31 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + pid_t pid; + char *buf; + int rc; + + if (argc != 2) { + fprintf(stderr, "usage: %s pid\n", argv[0]); + exit(1); + } + + if (sscanf(argv[1], "%d", &pid) != 1) { + fprintf(stderr, "%s: invalid pid %s\n", argv[0], argv[1]); + exit(2); + } + + rc = getpidcon(pid, &buf); + if (rc < 0) { + fprintf(stderr, "%s: getpidcon() failed\n", argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +}
diff --git a/selinux/libselinux/utils/getsebool.c b/selinux/libselinux/utils/getsebool.c new file mode 100644 index 0000000..9ae9243 --- /dev/null +++ b/selinux/libselinux/utils/getsebool.c
@@ -0,0 +1,113 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <errno.h> +#include <string.h> +#include <selinux/selinux.h> + +static void usage(const char *progname) +{ + fprintf(stderr, "usage: %s -a or %s boolean...\n", progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int i, get_all = 0, rc = 0, active, pending, len = 0, opt; + char **names; + + while ((opt = getopt(argc, argv, "a")) > 0) { + switch (opt) { + case 'a': + if (argc > 2) + usage(argv[0]); + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", + argv[0]); + return 1; + } + errno = 0; + rc = security_get_boolean_names(&names, &len); + if (rc) { + fprintf(stderr, + "%s: Unable to get boolean names: %s\n", + argv[0], strerror(errno)); + return 1; + } + if (!len) { + printf("No booleans\n"); + return 0; + } + get_all = 1; + break; + default: + usage(argv[0]); + } + } + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + + if (!len) { + if (argc < 2) + usage(argv[0]); + len = argc - 1; + names = malloc(sizeof(char *) * len); + if (!names) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + return 2; + } + for (i = 0; i < len; i++) { + names[i] = strdup(argv[i + 1]); + if (!names[i]) { + fprintf(stderr, "%s: out of memory\n", + argv[0]); + return 2; + } + } + } + + for (i = 0; i < len; i++) { + active = security_get_boolean_active(names[i]); + if (active < 0) { + if (get_all && errno == EACCES) + continue; + fprintf(stderr, "Error getting active value for %s\n", + names[i]); + rc = -1; + goto out; + } + pending = security_get_boolean_pending(names[i]); + if (pending < 0) { + fprintf(stderr, "Error getting pending value for %s\n", + names[i]); + rc = -1; + goto out; + } + char *alt_name = selinux_boolean_sub(names[i]); + if (! alt_name) { + perror("Out of memory\n"); + rc = -1; + goto out; + } + + if (pending != active) { + printf("%s --> %s pending: %s\n", alt_name, + (active ? "on" : "off"), + (pending ? "on" : "off")); + } else { + printf("%s --> %s\n", alt_name, + (active ? "on" : "off")); + } + free(alt_name); + } + + out: + for (i = 0; i < len; i++) + free(names[i]); + free(names); + return rc; +}
diff --git a/selinux/libselinux/utils/getseuser.c b/selinux/libselinux/utils/getseuser.c new file mode 100644 index 0000000..c33a4ad --- /dev/null +++ b/selinux/libselinux/utils/getseuser.c
@@ -0,0 +1,40 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <selinux/selinux.h> +#include <selinux/get_context_list.h> + +int main(int argc, char **argv) +{ + char *seuser = NULL, *level = NULL; + char **contextlist; + int rc, n, i; + + if (argc != 3) { + fprintf(stderr, "usage: %s linuxuser fromcon\n", argv[0]); + exit(1); + } + + rc = getseuserbyname(argv[1], &seuser, &level); + if (rc) { + fprintf(stderr, "getseuserbyname failed: %s\n", + strerror(errno)); + exit(2); + } + printf("seuser: %s, level %s\n", seuser, level); + n = get_ordered_context_list_with_level(seuser, level, argv[2], + &contextlist); + if (n <= 0) { + fprintf(stderr, + "get_ordered_context_list_with_level failed: %s\n", + strerror(errno)); + exit(3); + } + free(seuser); + free(level); + for (i = 0; i < n; i++) + printf("Context %d\t%s\n", i, contextlist[i]); + freeconary(contextlist); + exit(0); +}
diff --git a/selinux/libselinux/utils/matchpathcon.c b/selinux/libselinux/utils/matchpathcon.c new file mode 100644 index 0000000..d1f1348 --- /dev/null +++ b/selinux/libselinux/utils/matchpathcon.c
@@ -0,0 +1,201 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <selinux/selinux.h> +#include <limits.h> +#include <stdlib.h> + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-N] [-n] [-f file_contexts] [ -P policy_root_path ] [-p prefix] [-Vq] path...\n", + progname); + exit(1); +} + +static int printmatchpathcon(const char *path, int header, int mode) +{ + char *buf; + int rc = matchpathcon(path, mode, &buf); + if (rc < 0) { + if (errno == ENOENT) { + buf=strdup("<<none>>"); + } else { + fprintf(stderr, "matchpathcon(%s) failed: %s\n", path, + strerror(errno)); + return 1; + } + } + if (header) + printf("%s\t%s\n", path, buf); + else + printf("%s\n", buf); + + freecon(buf); + return 0; +} + +static mode_t string_to_mode(char *s) +{ + switch (s[0]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case 'f': + return S_IFREG; + default: + return -1; + }; + return -1; +} + +int main(int argc, char **argv) +{ + int i, init = 0, force_mode = 0; + int header = 1, opt; + int verify = 0; + int notrans = 0; + int error = 0; + int quiet = 0; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "m:Nnf:P:p:Vq")) > 0) { + switch (opt) { + case 'n': + header = 0; + break; + case 'm': + force_mode = string_to_mode(optarg); + if (force_mode < 0) { + fprintf(stderr, "%s: mode %s is invalid\n", argv[0], optarg); + exit(1); + } + break; + case 'V': + verify = 1; + break; + case 'N': + notrans = 1; + set_matchpathcon_flags(MATCHPATHCON_NOTRANS); + break; + case 'f': + if (init) { + fprintf(stderr, + "%s: -f and -p are exclusive\n", + argv[0]); + exit(1); + } + init = 1; + if (matchpathcon_init(optarg)) { + fprintf(stderr, + "Error while processing %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'P': + if (selinux_set_policy_root(optarg) < 0 ) { + fprintf(stderr, + "Error setting policy root %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'p': + if (init) { + fprintf(stderr, + "%s: -f and -p are exclusive\n", + argv[0]); + exit(1); + } + init = 1; + if (matchpathcon_init_prefix(NULL, optarg)) { + fprintf(stderr, + "Error while processing %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'q': + quiet = 1; + break; + default: + usage(argv[0]); + } + } + for (i = optind; i < argc; i++) { + int rc, mode = 0; + struct stat buf; + char *path = argv[i]; + int len = strlen(path); + if (len > 1 && path[len - 1 ] == '/') + path[len - 1 ] = '\0'; + + if (lstat(path, &buf) == 0) + mode = buf.st_mode; + if (force_mode) + mode = force_mode; + + if (verify) { + rc = selinux_file_context_verify(path, mode); + + if (quiet) { + if (rc == 1) + continue; + else + exit(1); + } + + if (rc == -1) { + printf("%s error: %s\n", path, strerror(errno)); + exit(1); + } else if (rc == 1) { + printf("%s verified.\n", path); + } else { + char * con; + error = 1; + if (notrans) + rc = lgetfilecon_raw(path, &con); + else + rc = lgetfilecon(path, &con); + + if (rc >= 0) { + printf("%s has context %s, should be ", + path, con); + printmatchpathcon(path, 0, mode); + freecon(con); + } else { + printf + ("actual context unknown: %s, should be ", + strerror(errno)); + printmatchpathcon(path, 0, mode); + } + } + } else { + error |= printmatchpathcon(path, header, mode); + } + } + matchpathcon_fini(); + return error; +}
diff --git a/selinux/libselinux/utils/policyvers.c b/selinux/libselinux/utils/policyvers.c new file mode 100644 index 0000000..0309d7d --- /dev/null +++ b/selinux/libselinux/utils/policyvers.c
@@ -0,0 +1,18 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(int argc __attribute__ ((unused)), char **argv) +{ + int rc; + + rc = security_policyvers(); + if (rc < 0) { + fprintf(stderr, "%s: policyvers() failed\n", argv[0]); + exit(2); + } + + printf("%d\n", rc); + exit(0); +}
diff --git a/selinux/libselinux/utils/sefcontext_compile.c b/selinux/libselinux/utils/sefcontext_compile.c new file mode 100644 index 0000000..d2578b6 --- /dev/null +++ b/selinux/libselinux/utils/sefcontext_compile.c
@@ -0,0 +1,440 @@ +#include <ctype.h> +#include <errno.h> +#include <pcre.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <getopt.h> +#include <limits.h> +#include <selinux/selinux.h> +#include <sepol/sepol.h> + +#include "../src/label_file.h" + +const char *policy_file; +static int ctx_err; + +static int validate_context(char **ctxp) +{ + char *ctx = *ctxp; + + if (policy_file && sepol_check_context(ctx) < 0) { + ctx_err = -1; + return ctx_err; + } + + return 0; +} + +static int process_file(struct selabel_handle *rec, const char *filename) +{ + unsigned int line_num; + int rc; + char *line_buf = NULL; + size_t line_len = 0; + FILE *context_file; + const char *prefix = NULL; + + context_file = fopen(filename, "r"); + if (!context_file) { + fprintf(stderr, "Error opening %s: %s\n", + filename, strerror(errno)); + return -1; + } + + line_num = 0; + rc = 0; + while (getline(&line_buf, &line_len, context_file) > 0) { + rc = process_line(rec, filename, prefix, line_buf, ++line_num); + if (rc || ctx_err) { + /* With -p option need to check and fail if ctx err as + * process_line() context validation on Linux does not + * return an error, but does print the error line to + * stderr. Android will set both to error and print + * the error line. */ + rc = -1; + goto out; + } + } +out: + free(line_buf); + fclose(context_file); + return rc; +} + +/* + * File Format + * + * u32 - magic number + * u32 - version + * u32 - length of pcre version EXCLUDING nul + * char - pcre version string EXCLUDING nul + * u32 - number of stems + * ** Stems + * u32 - length of stem EXCLUDING nul + * char - stem char array INCLUDING nul + * u32 - number of regexs + * ** Regexes + * u32 - length of upcoming context INCLUDING nul + * char - char array of the raw context + * u32 - length of the upcoming regex_str + * char - char array of the original regex string including the stem. + * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE + * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS + * s32 - stemid associated with the regex + * u32 - spec has meta characters + * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN + * u32 - data length of the pcre regex + * char - a bufer holding the raw pcre regex info + * u32 - data length of the pcre regex study daya + * char - a buffer holding the raw pcre regex study data + */ +static int write_binary_file(struct saved_data *data, int fd) +{ + struct spec *specs = data->spec_arr; + FILE *bin_file; + size_t len; + uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT; + uint32_t section_len; + uint32_t i; + int rc; + + bin_file = fdopen(fd, "w"); + if (!bin_file) { + perror("fopen output_file"); + exit(EXIT_FAILURE); + } + + /* write some magic number */ + len = fwrite(&magic, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write the version */ + section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write the pcre version */ + section_len = strlen(pcre_version()); + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + len = fwrite(pcre_version(), sizeof(char), section_len, bin_file); + if (len != section_len) + goto err; + + /* write the number of stems coming */ + section_len = data->num_stems; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + for (i = 0; i < section_len; i++) { + char *stem = data->stem_arr[i].buf; + uint32_t stem_len = data->stem_arr[i].len; + + /* write the strlen (aka no nul) */ + len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* include the nul in the file */ + stem_len += 1; + len = fwrite(stem, sizeof(char), stem_len, bin_file); + if (len != stem_len) + goto err; + } + + /* write the number of regexes coming */ + section_len = data->nspec; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + for (i = 0; i < section_len; i++) { + char *context = specs[i].lr.ctx_raw; + char *regex_str = specs[i].regex_str; + mode_t mode = specs[i].mode; + size_t prefix_len = specs[i].prefix_len; + int32_t stem_id = specs[i].stem_id; + pcre *re = specs[i].regex; + pcre_extra *sd = get_pcre_extra(&specs[i]); + uint32_t to_write; + size_t size; + + /* length of the context string (including nul) */ + to_write = strlen(context) + 1; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* original context strin (including nul) */ + len = fwrite(context, sizeof(char), to_write, bin_file); + if (len != to_write) + goto err; + + /* length of the original regex string (including nul) */ + to_write = strlen(regex_str) + 1; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* original regex string */ + len = fwrite(regex_str, sizeof(char), to_write, bin_file); + if (len != to_write) + goto err; + + /* binary F_MODE bits */ + to_write = mode; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* stem for this regex (could be -1) */ + len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file); + if (len != 1) + goto err; + + /* does this spec have a metaChar? */ + to_write = specs[i].hasMetaChars; + len = fwrite(&to_write, sizeof(to_write), 1, bin_file); + if (len != 1) + goto err; + + /* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */ + to_write = prefix_len; + len = fwrite(&to_write, sizeof(to_write), 1, bin_file); + if (len != 1) + goto err; + + /* determine the size of the pcre data in bytes */ + rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size); + if (rc < 0) + goto err; + + /* write the number of bytes in the pcre data */ + to_write = size; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write the actual pcre data as a char array */ + len = fwrite(re, 1, to_write, bin_file); + if (len != to_write) + goto err; + + /* determine the size of the pcre study info */ + rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size); + if (rc < 0) + goto err; + + /* write the number of bytes in the pcre study data */ + to_write = size; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write the actual pcre study data as a char array */ + len = fwrite(sd->study_data, 1, to_write, bin_file); + if (len != to_write) + goto err; + } + + rc = 0; +out: + fclose(bin_file); + return rc; +err: + rc = -1; + goto out; +} + +static void free_specs(struct saved_data *data) +{ + struct spec *specs = data->spec_arr; + unsigned int num_entries = data->nspec; + unsigned int i; + + for (i = 0; i < num_entries; i++) { + free(specs[i].lr.ctx_raw); + free(specs[i].lr.ctx_trans); + free(specs[i].regex_str); + free(specs[i].type_str); + pcre_free(specs[i].regex); + pcre_free_study(specs[i].sd); + } + free(specs); + + num_entries = data->num_stems; + for (i = 0; i < num_entries; i++) + free(data->stem_arr[i].buf); + free(data->stem_arr); + + memset(data, 0, sizeof(*data)); +} + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-o out_file] [-p policy_file] fc_file\n" + "Where:\n\t" + "-o Optional file name of the PCRE formatted binary\n\t" + " file to be output. If not specified the default\n\t" + " will be fc_file with the .bin suffix appended.\n\t" + "-p Optional binary policy file that will be used to\n\t" + " validate contexts defined in the fc_file.\n\t" + "fc_file The text based file contexts file to be processed.\n", + progname); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + const char *path = NULL; + const char *out_file = NULL; + char stack_path[PATH_MAX + 1]; + char *tmp = NULL; + int fd, rc, opt; + FILE *policy_fp = NULL; + struct stat buf; + struct selabel_handle *rec = NULL; + struct saved_data *data = NULL; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "o:p:")) > 0) { + switch (opt) { + case 'o': + out_file = optarg; + break; + case 'p': + policy_file = optarg; + break; + default: + usage(argv[0]); + } + } + + if (optind >= argc) + usage(argv[0]); + + path = argv[optind]; + if (stat(path, &buf) < 0) { + fprintf(stderr, "Can not stat: %s: %m\n", path); + exit(EXIT_FAILURE); + } + + /* Open binary policy if supplied. */ + if (policy_file) { + policy_fp = fopen(policy_file, "r"); + + if (!policy_fp) { + fprintf(stderr, "Failed to open policy: %s\n", + policy_file); + exit(EXIT_FAILURE); + } + + if (sepol_set_policydb_from_file(policy_fp) < 0) { + fprintf(stderr, "Failed to load policy: %s\n", + policy_file); + fclose(policy_fp); + exit(EXIT_FAILURE); + } + } + + /* Generate dummy handle for process_line() function */ + rec = (struct selabel_handle *)calloc(1, sizeof(*rec)); + if (!rec) { + fprintf(stderr, "Failed to calloc handle\n"); + if (policy_fp) + fclose(policy_fp); + exit(EXIT_FAILURE); + } + rec->backend = SELABEL_CTX_FILE; + + /* Need to set validation on to get the bin file generated by the + * process_line function, however as the bin file being generated + * may not be related to the currently loaded policy (that it + * would be validated against), then set callback to ignore any + * validation - unless the -p option is used in which case if an + * error is detected, the process will be aborted. */ + rec->validating = 1; + selinux_set_callback(SELINUX_CB_VALIDATE, + (union selinux_callback)&validate_context); + + data = (struct saved_data *)calloc(1, sizeof(*data)); + if (!data) { + fprintf(stderr, "Failed to calloc saved_data\n"); + free(rec); + if (policy_fp) + fclose(policy_fp); + exit(EXIT_FAILURE); + } + + rec->data = data; + + rc = process_file(rec, path); + if (rc < 0) + goto err; + + rc = sort_specs(data); + if (rc) + goto err; + + if (out_file) + rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file); + else + rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path); + + if (rc < 0 || rc >= (int)sizeof(stack_path)) + goto err; + + tmp = malloc(strlen(stack_path) + 7); + if (!tmp) + goto err; + + rc = sprintf(tmp, "%sXXXXXX", stack_path); + if (rc < 0) + goto err; + + fd = mkstemp(tmp); + if (fd < 0) + goto err; + + rc = fchmod(fd, buf.st_mode); + if (rc < 0) { + perror("fchmod failed to set permission on compiled regexs"); + goto err_unlink; + } + + rc = write_binary_file(data, fd); + if (rc < 0) + goto err_unlink; + + rc = rename(tmp, stack_path); + if (rc < 0) + goto err_unlink; + + rc = 0; +out: + if (policy_fp) + fclose(policy_fp); + + free_specs(data); + free(rec); + free(data); + free(tmp); + return rc; + +err_unlink: + unlink(tmp); +err: + rc = -1; + goto out; +}
diff --git a/selinux/libselinux/utils/selabel_digest.c b/selinux/libselinux/utils/selabel_digest.c new file mode 100644 index 0000000..1e9fb34 --- /dev/null +++ b/selinux/libselinux/utils/selabel_digest.c
@@ -0,0 +1,188 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <selinux/selinux.h> +#include <selinux/label.h> + +static size_t digest_len; + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n" + "Where:\n\t" + "-b The backend - \"file\", \"media\", \"x\", \"db\" or " + "\"prop\"\n\t" + "-v Run \"cat <specfile_list> | openssl dgst -sha1 -hex\"\n\t" + " on the list of specfiles to compare the SHA1 digests.\n\t" + "-B Use base specfiles only (valid for \"-b file\" only).\n\t" + "-i Do not request a digest.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\n", + progname); + exit(1); +} + +static int run_check_digest(char *cmd, char *selabel_digest) +{ + FILE *fp; + char files_digest[128]; + char *files_ptr; + int rc = 0; + + fp = popen(cmd, "r"); + if (!fp) { + printf("Failed to run command line\n"); + return -1; + } + + /* Only expect one line "(stdin)= x.." so read and find first space */ + while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL) + ; + + files_ptr = strstr(files_digest, " "); + + rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2); + if (rc) { + printf("Failed validation:\n\tselabel_digest: %s\n\t" + "files_digest: %s\n", + selabel_digest, files_ptr + 1); + } else { + printf("Passed validation - digest: %s\n", selabel_digest); + } + + pclose(fp); + return rc; +} + +int main(int argc, char **argv) +{ + int backend = 0, rc, opt, i, validate = 0; + char *baseonly = NULL, *file = NULL, *digest = (char *)1; + char **specfiles = NULL; + unsigned char *sha1_digest = NULL; + size_t num_specfiles; + + char cmd_buf[4096]; + char *cmd_ptr; + char *sha1_buf; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_BASEONLY, baseonly }, + { SELABEL_OPT_DIGEST, digest } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) { + switch (opt) { + case 'b': + if (!strcasecmp(optarg, "file")) { + backend = SELABEL_CTX_FILE; + } else if (!strcmp(optarg, "media")) { + backend = SELABEL_CTX_MEDIA; + } else if (!strcmp(optarg, "x")) { + backend = SELABEL_CTX_X; + } else if (!strcmp(optarg, "db")) { + backend = SELABEL_CTX_DB; + } else if (!strcmp(optarg, "prop")) { + backend = SELABEL_CTX_ANDROID_PROP; + } else { + fprintf(stderr, "Unknown backend: %s\n", + optarg); + usage(argv[0]); + } + break; + case 'B': + baseonly = (char *)1; + break; + case 'v': + validate = 1; + break; + case 'i': + digest = NULL; + break; + case 'f': + file = optarg; + break; + default: + usage(argv[0]); + } + } + + memset(cmd_buf, 0, sizeof(cmd_buf)); + + selabel_option[0].value = file; + selabel_option[1].value = baseonly; + selabel_option[2].value = digest; + + hnd = selabel_open(backend, selabel_option, 3); + if (!hnd) { + switch (errno) { + case EOVERFLOW: + fprintf(stderr, "ERROR Number of specfiles or specfile" + " buffer caused an overflow.\n"); + break; + default: + fprintf(stderr, "ERROR: selabel_open: %s\n", + strerror(errno)); + } + return -1; + } + + rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles, + &num_specfiles); + + if (rc) { + switch (errno) { + case EINVAL: + fprintf(stderr, "No digest available.\n"); + break; + default: + fprintf(stderr, "selabel_digest ERROR: %s\n", + strerror(errno)); + } + goto err; + } + + sha1_buf = malloc(digest_len * 2 + 1); + if (!sha1_buf) { + fprintf(stderr, "Could not malloc buffer ERROR: %s\n", + strerror(errno)); + rc = -1; + goto err; + } + + printf("SHA1 digest: "); + for (i = 0; i < digest_len; i++) + sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]); + + printf("%s\n", sha1_buf); + printf("calculated using the following specfile(s):\n"); + + if (specfiles) { + cmd_ptr = &cmd_buf[0]; + sprintf(cmd_ptr, "/usr/bin/cat "); + cmd_ptr = &cmd_buf[0] + strlen(cmd_buf); + + for (i = 0; i < num_specfiles; i++) { + sprintf(cmd_ptr, "%s ", specfiles[i]); + cmd_ptr += strlen(specfiles[i]) + 1; + printf("%s\n", specfiles[i]); + } + sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex"); + + if (validate) + rc = run_check_digest(cmd_buf, sha1_buf); + } + + free(sha1_buf); +err: + selabel_close(hnd); + return rc; +}
diff --git a/selinux/libselinux/utils/selabel_lookup.c b/selinux/libselinux/utils/selabel_lookup.c new file mode 100644 index 0000000..d0b1457 --- /dev/null +++ b/selinux/libselinux/utils/selabel_lookup.c
@@ -0,0 +1,126 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <selinux/selinux.h> +#include <selinux/label.h> + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s -b backend [-v] [-r] -k key [-t type] [-f file]\n\n" + "Where:\n\t" + "-b The backend - \"file\", \"media\", \"x\", \"db\" or " + "\"prop\"\n\t" + "-v Validate entries against loaded policy.\n\t" + "-r Use \"raw\" function.\n\t" + "-k Lookup key - Depends on backend.\n\t" + "-t Lookup type - Optional as depends on backend.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\n" + "Examples:\n\t" + "%s -v -b file -k /run -t 0\n\t" + " lookup with validation against the loaded policy, the\n\t" + " \"file\" backend for path \"/run\" with mode = 0\n\t" + "%s -r -b x -t 4 -k X11:ButtonPress\n\t" + " lookup_raw the \"X\" backend for type SELABEL_X_EVENT\n\t" + " using key \"X11:ButtonPress\"\n\n", + progname, progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int raw = 0, type = 0, backend = 0, rc, opt; + char *validate = NULL, *key = NULL, *context = NULL, *file = NULL; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "b:f:vrk:t:")) > 0) { + switch (opt) { + case 'b': + if (!strcasecmp(optarg, "file")) { + backend = SELABEL_CTX_FILE; + } else if (!strcmp(optarg, "media")) { + backend = SELABEL_CTX_MEDIA; + } else if (!strcmp(optarg, "x")) { + backend = SELABEL_CTX_X; + } else if (!strcmp(optarg, "db")) { + backend = SELABEL_CTX_DB; + } else if (!strcmp(optarg, "prop")) { + backend = SELABEL_CTX_ANDROID_PROP; + } else { + fprintf(stderr, "Unknown backend: %s\n", + optarg); + usage(argv[0]); + } + break; + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'r': + raw = 1; + break; + case 'k': + key = optarg; + break; + case 't': + type = atoi(optarg); + break; + default: + usage(argv[0]); + } + } + + selabel_option[0].value = file; + selabel_option[1].value = validate; + + hnd = selabel_open(backend, selabel_option, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + return -1; + } + + switch (raw) { + case 1: + rc = selabel_lookup_raw(hnd, &context, key, type); + break; + default: + rc = selabel_lookup(hnd, &context, key, type); + } + selabel_close(hnd); + + if (rc) { + switch (errno) { + case ENOENT: + fprintf(stderr, "ERROR: selabel_lookup failed to " + "find a valid context.\n"); + break; + case EINVAL: + fprintf(stderr, "ERROR: selabel_lookup failed to " + "validate context, or key / type are " + "invalid.\n"); + break; + default: + fprintf(stderr, "selabel_lookup ERROR: %s\n", + strerror(errno)); + } + } else { + printf("Default context: %s\n", context); + freecon(context); + } + + return rc; +}
diff --git a/selinux/libselinux/utils/selabel_lookup_best_match.c b/selinux/libselinux/utils/selabel_lookup_best_match.c new file mode 100644 index 0000000..d74382f --- /dev/null +++ b/selinux/libselinux/utils/selabel_lookup_best_match.c
@@ -0,0 +1,162 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <sys/stat.h> +#include <selinux/selinux.h> +#include <selinux/label.h> + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-v] [-r] -p path [-m mode] [-f file] [link...]\n\n" + "Where:\n\t" + "-v Validate file_contxts entries against loaded policy.\n\t" + "-r Use \"raw\" function.\n\t" + "-p Path to check for best match using the link(s) provided.\n\t" + "-m Optional mode (b, c, d, p, l, s or f) Defaults to 0.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\t" + "link Zero or more links to check against, the order of\n\t" + " precedence for best match is:\n\t\t" + " 1) An exact match for the real path (if no links), or\n\t\t" + " 2) An exact match for any of the links (aliases), or\n\t\t" + " 3) The longest fixed prefix match.\n\n" + "Example:\n\t" + "%s -p /dev/initctl /run/systemd/initctl/fifo\n\t" + " Find best matching context for the specified path using one link.\n\n", + progname, progname); + exit(1); +} + +static mode_t string_to_mode(char *s) +{ + switch (s[0]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case 'f': + return S_IFREG; + }; + return 0; +} + +int main(int argc, char **argv) +{ + int raw = 0, mode = 0, rc, opt, i, num_links, string_len; + char *validate = NULL, *path = NULL, *context = NULL, *file = NULL; + char **links = NULL; + + struct selabel_handle *hnd; + struct selinux_opt options[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "f:vrp:m:")) > 0) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'r': + raw = 1; + break; + case 'p': + path = optarg; + break; + case 'm': + mode = string_to_mode(optarg); + break; + default: + usage(argv[0]); + } + } + + /* Count links */ + for (i = optind, num_links = 0; i < argc; i++, num_links++) + ; + + if (num_links) { + links = calloc(num_links + 1, sizeof(char *)); + + if (!links) { + fprintf(stderr, "ERROR: calloc failed.\n"); + exit(1); + } + + for (i = optind, num_links = 0; i < argc; i++, num_links++) { + string_len = strlen(argv[i]) + 1; + links[num_links] = malloc(string_len); + if (!links[num_links]) { + fprintf(stderr, "ERROR: malloc failed.\n"); + exit(1); + } + strcpy(links[num_links], argv[i]); + } + } + + options[0].value = file; + options[1].value = validate; + + hnd = selabel_open(SELABEL_CTX_FILE, options, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + rc = -1; + goto out; + } + + if (raw) + rc = selabel_lookup_best_match_raw(hnd, &context, path, + (const char **)links, mode); + else + rc = selabel_lookup_best_match(hnd, &context, path, + (const char **)links, mode); + + selabel_close(hnd); + + if (rc) { + switch (errno) { + case ENOENT: + fprintf(stderr, "ERROR: selabel_lookup_best_match " + "failed to find a valid context.\n"); + break; + case EINVAL: + fprintf(stderr, "ERROR: selabel_lookup_best_match " + "failed to validate context, or path / mode " + "are invalid.\n"); + break; + default: + fprintf(stderr, "selabel_lookup_best_match ERROR: " + "%s\n", strerror(errno)); + } + } else { + printf("Best match context: %s\n", context); + freecon(context); + } + +out: + if (links) { + for (i = 0; links[i]; i++) + free(links[i]); + free(links); + } + + return rc; +}
diff --git a/selinux/libselinux/utils/selabel_partial_match.c b/selinux/libselinux/utils/selabel_partial_match.c new file mode 100644 index 0000000..017702d --- /dev/null +++ b/selinux/libselinux/utils/selabel_partial_match.c
@@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <stdbool.h> +#include <selinux/selinux.h> +#include <selinux/label.h> + +static void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -p <path> [-f file]\n\n" + "Where:\n\t" + "-v Validate file_contxts entries against loaded policy.\n\t" + "-p Path to check if a match or partial match is possible\n\t" + " against a regex entry in the file_contexts file.\n\t" + "-f Optional file_contexts file (defaults to current policy).\n\n" + "Example:\n\t" + "%s -p /sys/devices/system/cpu/online\n\t" + " Check if a match or partial match is possible against\n\t" + " the path \"/sys/devices/system/cpu/online\", returning\n\t" + " TRUE or FALSE.\n\n", progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt; + bool partial_match; + char *validate = NULL, *path = NULL, *file = NULL; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "f:vp:")) > 0) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'p': + path = optarg; + break; + default: + usage(argv[0]); + } + } + + selabel_option[0].value = file; + selabel_option[1].value = validate; + + hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + return -1; + } + + partial_match = selabel_partial_match(hnd, path); + + printf("Match or Partial match: %s\n", + partial_match == 1 ? "TRUE" : "FALSE"); + + selabel_close(hnd); + return partial_match; +}
diff --git a/selinux/libselinux/utils/selinux_check_securetty_context.c b/selinux/libselinux/utils/selinux_check_securetty_context.c new file mode 100644 index 0000000..b158eb3 --- /dev/null +++ b/selinux/libselinux/utils/selinux_check_securetty_context.c
@@ -0,0 +1,35 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <selinux/selinux.h> + +static void usage(const char *progname) +{ + fprintf(stderr, "usage: %s tty_context...\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int i; + if (argc < 2) + usage(argv[0]); + + for (i = 1; i < argc; i++) { + switch (selinux_check_securetty_context(argv[i])) { + case 0: + printf("%s securetty.\n", argv[i]); + break; + default: + printf("%s not securetty.\n", argv[i]); + break; + } + } + return 0; +}
diff --git a/selinux/libselinux/utils/selinux_restorecon.c b/selinux/libselinux/utils/selinux_restorecon.c new file mode 100644 index 0000000..52352c5 --- /dev/null +++ b/selinux/libselinux/utils/selinux_restorecon.c
@@ -0,0 +1,263 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <stdbool.h> +#include <sepol/sepol.h> +#include <selinux/label.h> +#include <selinux/restorecon.h> + +static char *policyfile; + +static char **exclude_list; +static int exclude_count; + +static int validate_context(char **contextp) +{ + char *context = *contextp, *tmpcon; + + if (policyfile) { + if (sepol_check_context(context) < 0) { + fprintf(stderr, "Invalid context %s\n", context); + exit(-1); + } + } else if (security_canonicalize_context_raw(context, &tmpcon) == 0) { + free(context); + *contextp = tmpcon; + } else if (errno != ENOENT) { + fprintf(stderr, "Validate context error: %s\n", + strerror(errno)); + exit(-1); + } + + return 0; +} + +static void usage(const char *progname) +{ + fprintf(stderr, + "\nusage: %s [-FCnRrdei] [-v|-P] [-p policy] [-f specfile] " + "pathname ...\n" + "Where:\n\t" + "-F Set the label to that in specfile.\n\t" + " If not set then reset the \"type\" component of the " + "label to that\n\t in the specfile.\n\t" + "-C Check labels even if the stored SHA1 digest matches\n\t" + " the specfiles SHA1 digest.\n\t" + "-n Don't change any file labels (passive check).\n\t" + "-R Recursively change file and directory labels.\n\t" + "-v Show changes in file labels (-v and -P are mutually " + " exclusive).\n\t" + "-P Show progress by printing \"*\" to stdout every 1000 files.\n\t" + "-r Use realpath(3) to convert pathnames to canonical form.\n\t" + "-d Prevent descending into directories that have a " + "different\n\t device number than the pathname from which " + "the descent began.\n\t" + "-e Exclude this file/directory (add multiple -e entries).\n\t" + "-i Do not set SELABEL_OPT_VALIDATE option in selabel_open(3)" + " then call\n\t selinux_restorecon_set_sehandle(3).\n\t" + "-p Optional binary policy file (also sets validate context " + "option).\n\t" + "-f Optional file contexts file.\n\t" + "pathname One or more paths to relabel.\n\n", + progname); + exit(-1); +} + +static void add_exclude(const char *directory) +{ + char **tmp_list; + + if (directory == NULL || directory[0] != '/') { + fprintf(stderr, "Full path required for exclude: %s.\n", + directory); + exit(-1); + } + + /* Add another two entries, one for directory, and the other to + * terminate the list */ + tmp_list = realloc(exclude_list, sizeof(char *) * (exclude_count + 2)); + if (!tmp_list) { + fprintf(stderr, "ERROR: realloc failed.\n"); + exit(-1); + } + exclude_list = tmp_list; + + exclude_list[exclude_count] = strdup(directory); + if (!exclude_list[exclude_count]) { + fprintf(stderr, "ERROR: strdup failed.\n"); + exit(-1); + } + exclude_count++; + exclude_list[exclude_count] = NULL; +} + +int main(int argc, char **argv) +{ + int opt, i; + unsigned int restorecon_flags = 0; + char *path = NULL, *digest = NULL, *validate = NULL; + FILE *policystream; + bool ignore_digest = false, require_selinux = true; + bool verbose = false, progress = false; + + struct selabel_handle *hnd = NULL; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, path }, + { SELABEL_OPT_DIGEST, digest }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 2) + usage(argv[0]); + + exclude_list = NULL; + exclude_count = 0; + + while ((opt = getopt(argc, argv, "iFCnRvPrde:f:p:")) > 0) { + switch (opt) { + case 'F': + restorecon_flags |= + SELINUX_RESTORECON_SET_SPECFILE_CTX; + break; + case 'C': + restorecon_flags |= + SELINUX_RESTORECON_IGNORE_DIGEST; + break; + case 'n': + restorecon_flags |= SELINUX_RESTORECON_NOCHANGE; + break; + case 'R': + restorecon_flags |= SELINUX_RESTORECON_RECURSE; + break; + case 'v': + if (progress) { + fprintf(stderr, + "Progress and Verbose are mutually exclusive\n"); + exit(-1); + } + verbose = true; + restorecon_flags |= SELINUX_RESTORECON_VERBOSE; + break; + case 'P': + if (verbose) { + fprintf(stderr, + "Progress and Verbose are mutually exclusive\n"); + exit(-1); + } + progress = true; + restorecon_flags |= SELINUX_RESTORECON_PROGRESS; + break; + case 'r': + restorecon_flags |= SELINUX_RESTORECON_REALPATH; + break; + case 'd': + restorecon_flags |= SELINUX_RESTORECON_XDEV; + break; + case 'e': + add_exclude(optarg); + break; + case 'p': + policyfile = optarg; + + policystream = fopen(policyfile, "r"); + if (!policystream) { + fprintf(stderr, + "ERROR: opening %s: %s\n", + policyfile, strerror(errno)); + exit(-1); + } + + if (sepol_set_policydb_from_file(policystream) < 0) { + fprintf(stderr, + "ERROR: reading policy %s: %s\n", + policyfile, strerror(errno)); + exit(-1); + } + fclose(policystream); + + selinux_set_callback(SELINUX_CB_VALIDATE, + (union selinux_callback)&validate_context); + require_selinux = false; + break; + case 'f': + path = optarg; + break; + case 'i': + ignore_digest = true; + break; + default: + usage(argv[0]); + } + } + + if (require_selinux && (is_selinux_enabled() <= 0)) { + fprintf(stderr, + "SELinux must be enabled to perform this operation.\n"); + exit(-1); + } + + if (optind >= argc) { + fprintf(stderr, "No pathname specified\n"); + exit(-1); + } + + /* If any of these set then do our own selabel_open and pass + * handle to selinux_restorecon */ + if (ignore_digest || path || policyfile) { + if (path) + selabel_option[0].value = path; + else + selabel_option[0].value = NULL; + + if (ignore_digest) + selabel_option[1].value = NULL; + else + selabel_option[1].value = (char *)1; + + if (policyfile) /* Validate */ + selabel_option[2].value = (char *)1; + else + selabel_option[2].value = NULL; + + hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 3); + if (!hnd) { + switch (errno) { + case EOVERFLOW: + fprintf(stderr, "ERROR: Number of specfiles or" + " specfile buffer caused an overflow.\n"); + break; + default: + fprintf(stderr, "ERROR: selabel_open: %s\n", + strerror(errno)); + } + exit(-1); + } + selinux_restorecon_set_sehandle(hnd); + } + + if (exclude_list) + selinux_restorecon_set_exclude_list + ((const char **)exclude_list); + + /* Call restorecon for each path in list */ + for (i = optind; i < argc; i++) { + if (selinux_restorecon(argv[i], restorecon_flags) < 0) { + fprintf(stderr, "ERROR: selinux_restorecon: %s\n", + strerror(errno)); + exit(-1); + } + } + + if (exclude_list) { + for (i = 0; exclude_list[i]; i++) + free(exclude_list[i]); + free(exclude_list); + } + + if (hnd) + selabel_close(hnd); + + return 0; +}
diff --git a/selinux/libselinux/utils/selinuxenabled.c b/selinux/libselinux/utils/selinuxenabled.c new file mode 100644 index 0000000..04ea778 --- /dev/null +++ b/selinux/libselinux/utils/selinuxenabled.c
@@ -0,0 +1,9 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(void) +{ + return !is_selinux_enabled(); +}
diff --git a/selinux/libselinux/utils/selinuxexeccon.c b/selinux/libselinux/utils/selinuxexeccon.c new file mode 100644 index 0000000..e0212e4 --- /dev/null +++ b/selinux/libselinux/utils/selinuxexeccon.c
@@ -0,0 +1,59 @@ +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <selinux/selinux.h> + +static void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s command [ fromcon ]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +static char * get_selinux_proc_context(const char *command, char * execcon) { + char * fcon = NULL, *newcon = NULL; + + int ret = getfilecon(command, &fcon); + if (ret < 0) goto err; + ret = security_compute_create(execcon, fcon, string_to_security_class("process"), &newcon); + if (ret < 0) goto err; + +err: + freecon(fcon); + return newcon; +} + +int main(int argc, char **argv) +{ + int ret = -1; + char * proccon = NULL, *con = NULL; + if (argc < 2 || argc > 3) + usage(argv[0], "Invalid number of arguments", -1); + + if (argc == 2) { + if (getcon(&con) < 0) { + perror(argv[0]); + return -1; + } + } else { + con = strdup(argv[2]); + } + + proccon = get_selinux_proc_context(argv[1], con); + if (proccon) { + printf("%s\n", proccon); + ret = 0; + } else { + perror(argv[0]); + } + + free(proccon); + free(con); + return ret; +}
diff --git a/selinux/libselinux/utils/setenforce.c b/selinux/libselinux/utils/setenforce.c new file mode 100644 index 0000000..df58597 --- /dev/null +++ b/selinux/libselinux/utils/setenforce.c
@@ -0,0 +1,42 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <selinux/selinux.h> + +static void usage(const char *progname) +{ + fprintf(stderr, "usage: %s [ Enforcing | Permissive | 1 | 0 ]\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int rc = 0; + if (argc != 2) { + usage(argv[0]); + } + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + if (strlen(argv[1]) == 1 && (argv[1][0] == '0' || argv[1][0] == '1')) { + rc = security_setenforce(atoi(argv[1])); + } else { + if (strcasecmp(argv[1], "enforcing") == 0) { + rc = security_setenforce(1); + } else if (strcasecmp(argv[1], "permissive") == 0) { + rc = security_setenforce(0); + } else + usage(argv[0]); + } + if (rc < 0) { + fprintf(stderr, "%s: setenforce() failed\n", argv[0]); + return 2; + } + return 0; +}
diff --git a/selinux/libselinux/utils/setfilecon.c b/selinux/libselinux/utils/setfilecon.c new file mode 100644 index 0000000..d69af84 --- /dev/null +++ b/selinux/libselinux/utils/setfilecon.c
@@ -0,0 +1,24 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <selinux/selinux.h> + +int main(int argc, char **argv) +{ + int rc, i; + + if (argc < 3) { + fprintf(stderr, "usage: %s context path...\n", argv[0]); + exit(1); + } + + for (i = 2; i < argc; i++) { + rc = setfilecon(argv[i], argv[1]); + if (rc < 0) { + fprintf(stderr, "%s: setfilecon(%s,%s) failed\n", + argv[0], argv[i], argv[1]); + exit(2); + } + } + exit(0); +}
diff --git a/selinux/libselinux/utils/togglesebool.c b/selinux/libselinux/utils/togglesebool.c new file mode 100644 index 0000000..309f83b --- /dev/null +++ b/selinux/libselinux/utils/togglesebool.c
@@ -0,0 +1,97 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <libgen.h> +#include <errno.h> +#include <selinux/selinux.h> +#include <syslog.h> +#include <pwd.h> +#include <string.h> + +/* Attempt to rollback the transaction. No need to check error + codes since this is rolling back something that blew up. */ +static void rollback(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + security_set_boolean(argv[i], + security_get_boolean_active(argv[i])); + exit(1); +} + +int main(int argc, char **argv) +{ + + int rc, i, commit = 0; + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + + if (argc < 2) { + printf("Usage: %s boolname1 [boolname2 ...]\n", + basename(argv[0])); + return 1; + } + + for (i = 1; i < argc; i++) { + printf("%s: ", argv[i]); + rc = security_get_boolean_active(argv[i]); + switch (rc) { + case 1: + if (security_set_boolean(argv[i], 0) >= 0) { + printf("inactive\n"); + commit++; + } else { + printf("%s - rolling back all changes\n", + strerror(errno)); + rollback(i, argv); + } + break; + case 0: + if (security_set_boolean(argv[i], 1) >= 0) { + printf("active\n"); + commit++; + } else { + printf("%s - rolling back all changes\n", + strerror(errno)); + rollback(i, argv); + } + break; + default: + if (errno == ENOENT) + printf + ("Boolean does not exist - rolling back all changes.\n"); + else + printf("%s - rolling back all changes.\n", + strerror(errno)); + rollback(i, argv); + break; /* Not reached. */ + } + } + + if (commit > 0) { + if (security_commit_booleans() < 0) { + printf("Commit failed. (%s) No change to booleans.\n", + strerror(errno)); + } else { + /* syslog all the changes */ + struct passwd *pwd = getpwuid(getuid()); + for (i = 1; i < argc; i++) { + if (pwd && pwd->pw_name) + syslog(LOG_NOTICE, + "The %s policy boolean was toggled by %s", + argv[i], pwd->pw_name); + else + syslog(LOG_NOTICE, + "The %s policy boolean was toggled by uid:%u", + argv[i], getuid()); + + } + return 0; + } + } + return 1; +}
diff --git a/selinux/libsemanage/COPYING b/selinux/libsemanage/COPYING new file mode 100644 index 0000000..8add30a --- /dev/null +++ b/selinux/libsemanage/COPYING
@@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +
diff --git a/selinux/libsemanage/ChangeLog b/selinux/libsemanage/ChangeLog new file mode 100644 index 0000000..3ef0e71 --- /dev/null +++ b/selinux/libsemanage/ChangeLog
@@ -0,0 +1,860 @@ + * Support overriding Makefile RANLIB, from Julien Pivotto. + * Respect CC and PKG_CONFIG environment variable, from Julien Pivotto. + * Fix multiple spelling errors, from Laurent Bigonville. + * genhomedircon: %{USERID} and %{USERNAME} support and code cleanups, from Jason Zaman. + +2.5 2016-02-23 + * Do not overwrite CFLAGS in test Makefile, from Nicolas Iooss. + * Fix uninitialized variable in direct_commit and direct_api, from Nicolas Iooss. + * semanage_migrate_store: Load libsepol.so.1 instead of libsepol.so, from Laurent Bigonville. + * Store homedir_template and users_extra in policy store, from Steve Lawrence + * Fix null pointer dereference in semanage_module_key_destroy, from Yuli Khodorkovskiy. + * Add semanage_module_extract() to extract a module as CIL or HLL, from Yuli Khodorkovskiy. + * semanage_migrate_store: add -r <root> option for migrating inside chroots, from Petr Lautrbach. + * Add file_contexts and seusers to the store, from Yuli Khodorkovskiy. + * Add policy binary and file_contexts.local to the store, from Yuli Khodorkovskiy. + * Allow to install compressed modules without a compression extension, + from Petr Lautrbach. + * Do not copy contexts in semanage_migrate_store, from Jason Zaman. + * Fix logic in bunzip for uncompressed pp files, from Thomas Hurd. + * Fix fname[] initialization in test_utilities.c, from Petr Lautrbach. + * Add remove-hll semanage.conf option to remove HLL files after + compilation to CIL, from Yuli Khodorkovskiy + * Fix memory leaks when parsing semanage.conf, from Yuli Khodorkovskiy + * Change bunzip to use heap instead of stack to prevent segfault on + systems with small stack size, from Thomas Hurd. + +2.4 2015-02-02 + * Fix Makefile to allow LIBDIR and SHLIBDIR to be set to different + directories, from Steve Lawrence + * Fix bugs found by hardened gcc flags, from Nicolas Iooss. + * Add missing manpage links to security_load_policy, from Laurent + Bigonville. + * Fix failing libsemanage pywrap tests, from Nicolas Iooss + * Fix deprecation warning for bison, from Ilya Frolov + * Skip policy module relink when only setting booleans, from Stephen + Smalley + * Fix typo in tests makefile, from Caleb Case + * Only try to compile file contexts if they exist, from Steve Lawrence + * Fix memory leak when setting a custom store path, from Yuli + Khodorkovskiy + * Add semodule option to set store root path in semanage.conf and the + semodule command, from Yuli Khodorkovskiy + * Add semanage.conf option to set an alternative root path for policy + store, from Yuli Khodorkovskiy + * Add support for High Level Language (HLL) to CIL compilers. The HLL + compiler path is configurable, but should be placed in + /usr/libexec/selinux/hll by default, from Yuli Khodorkovskiy + * Create a policy migration script for migrating the policy store from + /etc/selinux to /var/lib/selinux, from Caleb Case + * Add python3 support to the migration script, from Jason Zaman + * Use libcil to compile modules, from Steve Lawrence + * Use symbolic versioning to maintain ABI compatibility for old install + functions, from Yuli Khodorkovskiy + * Add a target-platform option to semanage.conf to control how policies + are built, from Steve Lawrence + * Add API to handle modules and source policies, moving module store to + /var/lib/selinux, from Caleb Case + * Only try to compile file contexts if they exist, from Steve Lawrence + +2.3 2014-05-06 + * Fix memory leak in semanage_genhomedircon from Thomas Hurd. + +2.2 2013-10-30 + * Avoid duplicate list entries from Dan Walsh. + * Add audit support to libsemanage from Dan Walsh. + * Remove policy.kern and replace with symlink from Dan Walsh. + * Apply a MAX_UID check for genhomedircon from Laurent Bigonville. + * Fix man pages from Laurent Bigonville. + +2.1.10 2013-02-01 + * Add sefcontext_compile to compile regex everytime policy is rebuilt + * Cleanup/fix enable/disable/remove module. + * redo genhomedircon minuid + * fixes from coverity + * semanage_store: do not leak memory in semanage_exec_prog + * genhomedircon: remove useless conditional in get_home_dirs + * genhomedircon: double free in get_home_dirs + * fcontext_record: do not leak on error in semanage_fcontext_key_create + * genhomedircon: do not leak on failure in write_gen_home_dir_context + * semanage_store: do not leak fd + * genhomedircon: do not leak shells list + * semanage_store: do not leak on strdup failure + * semanage_store: rewrite for readability + +2.1.9 2012-09-13 + * libsemanage: do not set soname needlessly + * libsemanage: remove PYTHONLIBDIR and ruby equivalent + * do boolean name substitution + * Fix segfault for building standard policies. + +2.1.8 2012-06-28 + * remove build warning when build swig c files + * additional makefile support for rubywrap + * ignore 80 column limit for readability + * semanage_store: fix snprintf length argument by using asprintf + * Use default semanage.conf as a fallback + * use after free in python bindings + +2.1.7 2012-03-28 + * Alternate path for semanage.conf + * do not link against libpython, this is considered bad in Debian + * Allow to build for several ruby version + * fallback-user-level + +2.1.6 2011-12-21 + * add ignoredirs config for genhomedircon + * Fallback_user_level can be NULL if you are not using MLS + +2.1.5 2011-11-03 + * regenerate .pc on VERSION change + * maintain mode even if umask is tighter + * semanage.conf man page + * create man5dir if not exist + +2.1.4 2011-09-15 + * Create a new preserve_tunables flag + * tree: default make target to all not + * fix semanage_store_access_check calling arguments + +2.1.3 2011-08-26 + * python wrapper makefile changes + +2.1.2 2011-08-17 + * print error debug info for buggy fc + * introduce semanage_set_root and friends + * throw exceptions in python rather than return + * python3 support. + * patch for MCS/MLS in user files + +2.1.1 2011-08-01 + * Remove generated files, expand .gitignore + * Use -Werror and change a few prototypes to support it + +2.1.0 2011-07-27 + * Release, minor version bump + +2.0.46 2010-12-16 + * Fix compliation under GCC 4.6 by Justin Mattock + +2.0.45 2010-03-06 + * Add enable/disable patch support from Dan Walsh. + * Add usepasswd flag to semanage.conf to disable genhomedircon using + passwd from Dan Walsh. + * regenerate swig wrappers + +2.0.44 2010-02-02 + * Replace usage of fmemopen() with sepol_policy_file_set_mem() since + glibc < 2.9 does not support binary mode ('b') for fmemopen'd + streams. + +2.0.43 2009-11-27 + * Move libsemanage.so to /usr/lib + * Add NAME lines to man pages from Manoj Srivastava<srivasta@debian.org> + +2.0.42 2009-11-18 + * Move load_policy from /usr/sbin to /sbin from Dan Walsh. + +2.0.41 2009-10-29 + * Add pkgconfig file from Eamon Walsh. + +2.0.40 2009-10-22 + * Add semanage_set_check_contexts() function to disable calling + setfiles + +2.0.39 2009-09-24 + * make swigify + +2.0.38 2009-09-16 + * Change semodule upgrade behavior to install even if the module + is not present from Dan Walsh. + * Make genhomedircon trim excess '/' from homedirs from Dan Walsh. + +2.0.37 2009-09-04 + * Fix persistent dontaudit support to rebuild policy if the + dontaudit state is changed from Chad Sellers. + +2.0.36 2009-08-24 + * Changed bzip-blocksize=0 handling to support existing compressed + modules in the store. + +2.0.35 2009-08-05 + * Revert hard linking of files between tmp/active/previous. + +2.0.34 2009-08-05 + * Enable configuration of bzip behavior from Stephen Smalley. + bzip-blocksize=0 to disable compression and decompression support. + bzip-blocksize=1..9 to set the blocksize for compression. + bzip-small=true to reduce memory usage for decompression. + +2.0.33 2009-07-07 + * Maintain disable dontaudit state from Christopher Pardy. + +2.0.32 2009-05-28 + * Ruby bindings from David Quigley. + +2.0.31 2009-01-12 + * Policy module compression (bzip) support from Dan Walsh. + * Hard link files between tmp/active/previous from Dan Walsh. + +2.0.30 2008-11-12 + * Add semanage_mls_enabled() interface from Stephen Smalley. + +2.0.29 2008-11-11 + * Add USER to lines to homedir_template context file from Chris PeBenito. + +2.0.28 2008-09-15 + * allow fcontext and seuser changes without rebuilding the policy from Dan Walsh + +2.0.27 2008-08-05 + * Modify genhomedircon to skip %groupname entries. + Ultimately we need to expand them to the list of users to support per-role homedir labeling when using the %groupname syntax. + +2.0.26 2008-07-29 + * Fix bug in genhomedircon fcontext matches logic from Dan Walsh. + Strip any trailing slash before appending /*$. + +2.0.25 2008-04-21 + * Do not call genhomedircon if the policy was not rebuilt from Stephen Smalley. + Fixes semanage boolean -D seg fault (bug 441379). + +2.0.24 2008-02-26 + * make swigify + +2.0.23 2008-02-04 + * Use vfork rather than fork for libsemanage helpers to reduce memory overhead as suggested by Todd Miller. + +2.0.22 2008-02-04 + * Free policydb before fork from Joshua Brindle. + +2.0.21 2008-02-04 + * Drop the base module immediately after expanding to permit memory re-use from Stephen Smalley. + +2.0.12 2008-02-02 + * Use sepol_set_expand_consume_base to reduce peak memory usage when + using semodule from Joshua Brindle. + +2.0.19 2008-01-31 + * Fix genhomedircon to not override a file context with a homedir context from Todd Miller. + +2.0.18 2008-01-28 + * Fix spurious out of memory error reports. + +2.0.17 2008-01-25 + * Merged second version of fix for genhomedircon handling from Caleb Case. + +2.0.16 2008-01-24 + * Merged fix for genhomedircon handling of missing HOME_DIR or HOME_ROOT templates from Caleb Case. + +2.0.15 2007-12-05 + * Fix genhomedircon handling of shells and missing user context template from Dan Walsh. + * Copy the store path in semanage_select_store from Dan Walsh. + +2.0.14 2007-11-05 + * Call rmdir() rather than remove() on directory removal so that errno isn't polluted from Stephen Smalley. + +2.0.13 2007-11-05 + * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley. + +2.0.12 2007-10-05 + * ustr cleanups from James Antill. + * Ensure that /root gets labeled even if using the default context from Dan Walsh. + +2.0.11 2007-09-28 + * Fix ordering of file_contexts.homedirs from Todd Miller and Dan Walsh. + +2.0.10 2007-09-28 + * Fix error checking on getpw*_r functions from Todd Miller. + * Make genhomedircon skip invalid homedir contexts from Todd Miller. + * Set default user and prefix from seusers from Dan Walsh. + * Add swigify Makefile target from Dan Walsh. + +2.0.9 2007-09-24 + * Pass CFLAGS to CC even on link command, per Dennis Gilmore. + +2.0.8 2007-09-19 + * Clear errno on non-fatal errors to avoid reporting them upon a + later error that does not set errno. + +2.0.7 2007-09-19 + * Improve reporting of system errors, e.g. full filesystem or read-only filesystem from Stephen Smalley. + +2.0.6 2007-09-10 + * Change to use getpw* function calls to the _r versions from Todd Miller. + +2.0.5 2007-08-23 + * Replace genhomedircon script with equivalent functionality within + libsemanage and introduce disable-genhomedircon option in + semanage.conf from Todd Miller. + Note: Depends on ustr. + +2.0.4 2007-08-16 + * Allow dontaudits to be turned off via semanage interface when + updating policy from Joshua Brindle. + +2.0.3 2007-04-25 + * Fix to libsemanage man patches so whatis will work better from Dan Walsh + +2.0.2 2007-04-24 + * Merged optimizations from Stephen Smalley. + - do not set all booleans upon commit, only those whose values have changed + - only install the sandbox upon commit if something was rebuilt + +2.0.1 2007-03-12 + * Merged dbase_file_flush patch from Dan Walsh. + This removes any mention of specific tools (e.g. semanage) + from the comment header of the auto-generated files, + since there are multiple front-end tools. + +2.0.0 2007-02-20 + * Merged Makefile test target patch from Caleb Case. + * Merged get_commit_number function rename patch from Caleb Case. + * Merged strnlen -> strlen patch from Todd Miller. + +1.10.1 2007-01-26 + * Merged python binding fix from Dan Walsh. + +1.10.0 2007-01-18 + * Updated version for stable branch. + +1.9.2 2007-01-08 + * Merged patch to optionally reduce disk usage by removing + the backup module store and linked policy from Karl MacMillan + * Merged patch to correctly propagate return values in libsemanage + +1.9.1 2006-11-27 + * Merged patch to compile wit -fPIC instead of -fpic from + Manoj Srivastava to prevent hitting the global offest table + limit. Patch changed to include libselinux and libsemanage in + addition to libsepol. + +1.8 2006-10-17 + * Updated version for release. + +1.6.17 2006-09-29 + * Merged patch to skip reload if no active store exists and + the store path doesn't match the active store path from Dan Walsh. + * Merged patch to not destroy sepol handle on error path of + connect from James Athey. + * Merged patch to add genhomedircon path to semanage.conf from + James Athey. + +1.6.16 2006-08-14 + * Make most copy errors fatal, but allow exceptions for + file_contexts.local, seusers, and netfilter_contexts if + the source file does not exist in the store. + +1.6.15 2006-08-11 + * Merged separate local file contexts patch from Chris PeBenito. + +1.6.14 2006-08-11 + * Merged patch to make most copy errors non-fatal from Dan Walsh. + +1.6.13 2006-08-03 + * Merged netfilter contexts support from Chris PeBenito. + +1.6.12 2006-07-11 + * Merged support for read operations on read-only fs from + Caleb Case (Tresys Technology). + +1.6.11 2006-06-29 + * Lindent. + +1.6.10 2006-06-26 + * Merged setfiles location check patch from Dan Walsh. + +1.6.9 2006-06-16 + * Merged several fixes from Serge Hallyn: + dbase_file_cache: deref of uninit data on error path. + dbase_policydb_cache: clear fp to avoid double fclose + semanage_fc_sort: destroy temp on error paths + +1.6.8 2006-06-02 + * Updated default location for setfiles to /sbin to + match policycoreutils. This can also be adjusted via + semanage.conf using the syntax: + [setfiles] + path = /path/to/setfiles + args = -q -c $@ $< + [end] + +1.6.7 2006-05-05 + * Merged fix warnings patch from Karl MacMillan. + +1.6.6 2006-04-14 + * Merged updated file context sorting patch from Christopher + Ashworth, with bug fix for escaped character flag. + +1.6.5 2006-04-13 + * Merged file context sorting code from Christopher Ashworth + (Tresys Technology), based on fc_sort.c code in refpolicy. + +1.6.4 2006-04-12 + * Merged python binding t_output_helper removal patch from Dan Walsh. + * Regenerated swig files. + +1.6.3 2006-03-30 + * Merged corrected fix for descriptor leak from Dan Walsh. + +1.6.2 2006-03-20 + * Merged Makefile PYLIBVER definition patch from Dan Walsh. + +1.6.1 2006-03-20 + * Merged man page reorganization from Ivan Gyurdiev. + +1.6 2006-03-14 + * Updated version for release. + +1.5.31 2006-03-09 + * Merged abort early on merge errors patch from Ivan Gyurdiev. + +1.5.30 2006-03-08 + * Cleaned up error handling in semanage_split_fc based on a patch + by Serge Hallyn (IBM) and suggestions by Ivan Gyurdiev. + +1.5.29 2006-02-21 + * Merged MLS handling fixes from Ivan Gyurdiev. + +1.5.28 2006-02-16 + * Merged bug fix for fcontext validate handler from Ivan Gyurdiev. + +1.5.27 2006-02-16 + * Merged base_merge_components changes from Ivan Gyurdiev. + +1.5.26 2006-02-15 + * Merged paths array patch from Ivan Gyurdiev. + * Merged bug fix patch from Ivan Gyurdiev. + +1.5.25 2006-02-14 + * Merged improve bindings patch from Ivan Gyurdiev. + +1.5.24 2006-02-14 + * Merged use PyList patch from Ivan Gyurdiev. + * Merged memory leak fix patch from Ivan Gyurdiev. + * Merged nodecon support patch from Ivan Gyurdiev. + * Merged cleanups patch from Ivan Gyurdiev. + * Merged split swig patch from Ivan Gyurdiev. + +1.5.23 2006-02-13 + * Merged optionals in base patch from Joshua Brindle. + +1.5.22 2006-02-13 + * Merged treat seusers/users_extra as optional sections patch from + Ivan Gyurdiev. + * Merged parse_optional fixes from Ivan Gyurdiev. + +1.5.21 2006-02-07 + * Merged seuser/user_extra support patch from Joshua Brindle. + * Merged remote system dbase patch from Ivan Gyurdiev. + +1.5.20 2006-02-02 + * Merged clone record on set_con patch from Ivan Gyurdiev. + +1.5.19 2006-01-30 + * Merged fname parameter patch from Ivan Gyurdiev. + * Merged more size_t -> unsigned int fixes from Ivan Gyurdiev. + * Merged seusers.system patch from Ivan Gyurdiev. + * Merged improve port/fcontext API patch from Ivan Gyurdiev. + +1.5.18 2006-01-27 + * Merged seuser -> seuser_local rename patch from Ivan Gyurdiev. + +1.5.17 2006-01-27 + * Merged set_create_store, access_check, and is_connected interfaces + from Joshua Brindle. + +1.5.16 2006-01-19 + * Regenerate python wrappers. + +1.5.15 2006-01-18 + * Merged pywrap Makefile diff from Dan Walsh. + * Merged cache management patch from Ivan Gyurdiev. + * Merged bugfix for dbase_llist_clear from Ivan Gyurdiev. + * Merged remove apply_local function patch from Ivan Gyurdiev. + * Merged only do read locking in direct case patch from Ivan Gyurdiev. + * Merged cache error path memory leak fix from Ivan Gyurdiev. + * Merged auto-generated file header patch from Ivan Gyurdiev. + * Merged pywrap test update from Ivan Gyurdiev. + * Merged hidden defs update from Ivan Gyurdiev. + +1.5.14 2006-01-13 + * Merged disallow port overlap patch from Ivan Gyurdiev. + +1.5.13 2006-01-12 + * Merged join prereq and implementation patches from Ivan Gyurdiev. + * Merged join user extra data part 2 patch from Ivan Gyurdiev. + * Merged bugfix patch from Ivan Gyurdiev. + +1.5.12 2006-01-12 + * Merged remove add_local/set_local patch from Ivan Gyurdiev. + * Merged user extra data part 1 patch from Ivan Gyurdiev. + * Merged size_t -> unsigned int patch from Ivan Gyurdiev. + * Merged calloc check in semanage_store patch from Ivan Gyurdiev, + bug noticed by Steve Grubb. + * Merged cleanups after add/set removal patch from Ivan Gyurdiev. + +1.5.11 2006-01-09 + * Merged fcontext compare fix from Ivan Gyurdiev. + +1.5.10 2006-01-06 + * Fixed commit to return the commit number aka policy sequence number. + +1.5.9 2006-01-06 + * Merged const in APIs patch from Ivan Gyurdiev. + * Merged validation of local file contexts patch from Ivan Gyurdiev. + * Merged compare2 function patch from Ivan Gyurdiev. + * Merged hidden def/proto update patch from Ivan Gyurdiev. + +1.5.8 2006-01-05 + * Re-applied string and file optimization patch from Russell Coker, + with bug fix. + +1.5.7 2006-01-05 + * Reverted string and file optimization patch from Russell Coker. + +1.5.6 2006-01-05 + * Clarified error messages from parse_module_headers and + parse_base_headers for base/module mismatches. + +1.5.5 2006-01-05 + * Merged string and file optimization patch from Russell Coker. + * Merged swig header reordering patch from Ivan Gyurdiev. + * Merged toggle modify on add patch from Ivan Gyurdiev. + * Merged ports parser bugfix patch from Ivan Gyurdiev. + * Merged fcontext swig patch from Ivan Gyurdiev. + * Merged remove add/modify/delete for active booleans patch from Ivan Gyurdiev. + * Merged man pages for dbase functions patch from Ivan Gyurdiev. + * Merged pywrap tests patch from Ivan Gyurdiev. + +1.5.4 2006-01-04 + * Merged patch series from Ivan Gyurdiev. + This includes patches to: + - separate file rw code from linked list + - annotate objects + - fold together internal headers + - support ordering of records in compare function + - add active dbase backend, active booleans + - return commit numbers for ro database calls + - use modified flags to skip rebuild whenever possible + - enable port interfaces + - update swig interfaces and typemaps + - add an API for file_contexts.local and file_contexts + - flip the traversal order in iterate/list + - reorganize sandbox_expand + - add seusers MLS validation + - improve dbase spec/documentation + - clone record on set/add/modify + +1.5.3 2005-12-14 + * Merged further header cleanups from Ivan Gyurdiev. + +1.5.2 2005-12-13 + * Merged toggle modified flag in policydb_modify, fix memory leak + in clear_obsolete, polymorphism vs headers fix, and include guards + for internal headers patches from Ivan Gyurdiev. + +1.5.1 2005-12-12 + * Added file-mode= setting to semanage.conf, default to 0644. + Changed semanage_copy_file and callers to use this mode when + installing policy files to runtime locations. + +1.4 2005-12-07 + * Updated version for release. + +1.3.64 2005-12-06 + * Changed semanage_handle_create() to set do_reload based on + is_selinux_enabled(). This prevents improper attempts to + load policy on a non-SELinux system. + +1.3.63 2005-12-05 + * Dropped handle from user_del_role interface. + +1.3.62 2005-12-05 + * Removed defrole interfaces. + +1.3.61 2005-11-29 + * Merged Makefile python definitions patch from Dan Walsh. + +1.3.60 2005-11-29 + * Removed is_selinux_mls_enabled() conditionals in seusers and users + file parsers. + +1.3.59 2005-11-28 + * Merged wrap char*** for user_get_roles patch from Joshua Brindle. + +1.3.58 2005-11-28 + * Merged remove defrole from sepol patch from Ivan Gyurdiev. + +1.3.57 2005-11-28 + * Merged swig wrappers for modifying users and seusers from Joshua Brindle. + +1.3.56 2005-11-16 + * Fixed free->key_free bug. + +1.3.55 2005-11-16 + * Merged clear obsolete patch from Ivan Gyurdiev. + +1.3.54 2005-11-15 + * Merged modified swigify patch from Dan Walsh + (original patch from Joshua Brindle). + * Merged move genhomedircon call patch from Chad Sellers. + +1.3.53 2005-11-10 + * Merged move seuser validation patch from Ivan Gyurdiev. + * Merged hidden declaration fixes from Ivan Gyurdiev, + with minor corrections. + +1.3.52 2005-11-09 + * Merged cleanup patch from Ivan Gyurdiev. + This renames semanage_module_conn to semanage_direct_handle, + and moves sepol handle create/destroy into semanage handle + create/destroy to allow use even when disconnected (for the + record interfaces). + +1.3.51 2005-11-08 + * Clear modules modified flag upon disconnect and commit. + +1.3.50 2005-11-08 + * Added tracking of module modifications and use it to + determine whether expand-time checks should be applied + on commit. + +1.3.49 2005-11-08 + * Reverted semanage_set_reload_bools() interface. + +1.3.48 2005-11-08 + * Disabled calls to port dbase for merge and commit and stubbed + out calls to sepol_port interfaces since they are not exported. + +1.3.47 2005-11-08 + * Merged rename instead of copy patch from Joshua Brindle (Tresys). + +1.3.46 2005-11-07 + * Added hidden_def/hidden_proto for exported symbols used within + libsemanage to eliminate relocations. Wrapped type definitions + in exported headers as needed to avoid conflicts. Added + src/context_internal.h and src/iface_internal.h. + +1.3.45 2005-11-07 + * Added semanage_is_managed() interface to allow detection of whether + the policy is managed via libsemanage. This enables proper handling + in setsebool for non-managed systems. + +1.3.44 2005-11-07 + * Merged semanage_set_reload_bools() interface from Ivan Gyurdiev, + to enable runtime control over preserving active boolean values + versus reloading their saved settings upon commit. + +1.3.43 2005-11-04 + * Merged seuser parser resync, dbase tracking and cleanup, strtol + bug, copyright, and assert space patches from Ivan Gyurdiev. + +1.3.42 2005-11-04 + * Added src/*_internal.h in preparation for other changes. + * Added hidden/hidden_proto/hidden_def to src/debug.[hc] and + src/seusers.[hc]. + +1.3.41 2005-11-03 + * Merged interface parse/print, context_to_string interface change, + move assert_noeof, and order preserving patches from Ivan Gyurdiev. + * Added src/dso.h in preparation for other changes. + +1.3.40 2005-11-01 + * Merged install seusers, handle/error messages, MLS parsing, + and seusers validation patches from Ivan Gyurdiev. + +1.3.39 2005-10-31 + * Merged record interface, dbase flush, common database code, + and record bugfix patches from Ivan Gyurdiev. + +1.3.38 2005-10-27 + * Merged dbase policydb list and count change from Ivan Gyurdiev. + +1.3.37 2005-10-27 + * Merged enable dbase and set relay patches from Ivan Gyurdiev. + +1.3.36 2005-10-27 + * Merged query APIs and dbase_file_set patches from Ivan Gyurdiev. + +1.3.35 2005-10-26 + * Merged sepol handle passing, seusers support, and policydb cache + patches from Ivan Gyurdiev. + +1.3.34 2005-10-25 + * Merged resync to sepol changes and booleans fixes/improvements + patches from Ivan Gyurdiev. + +1.3.33 2005-10-25 + * Merged support for genhomedircon/homedir template, store selection, + explicit policy reload, and semanage.conf relocation from Joshua + Brindle. + +1.3.32 2005-10-24 + * Merged resync to sepol changes and transaction fix patches from + Ivan Gyurdiev. + +1.3.31 2005-10-21 + * Merged reorganize users patch from Ivan Gyurdiev. + * Merged remove unused relay functions patch from Ivan Gyurdiev. + +1.3.30 2005-10-20 + * Fixed policy file leaks in semanage_load_module and + semanage_write_module. + * Merged further database work from Ivan Gyurdiev. + +1.3.29 2005-10-20 + * Fixed bug in semanage_direct_disconnect. + +1.3.28 2005-10-20 + * Merged interface renaming patch from Ivan Gyurdiev. + * Merged policy component patch from Ivan Gyurdiev. + +1.3.27 2005-10-20 + * Renamed 'check=' configuration value to 'expand-check=' for + clarity. + * Changed semanage_commit_sandbox to check for and report errors + on rename(2) calls performed during rollback. + +1.3.26 2005-10-19 + * Added optional check= configuration value to semanage.conf + and updated call to sepol_expand_module to pass its value + to control assertion and hierarchy checking on module expansion. + +1.3.25 2005-10-19 + * Merged fixes for make DESTDIR= builds from Joshua Brindle. + +1.3.24 2005-10-19 + * Merged default database from Ivan Gyurdiev. + * Merged removal of connect requirement in policydb backend from + Ivan Gyurdiev. + * Merged commit locking fix and lock rename from Joshua Brindle. + * Merged transaction rollback in lock patch from Joshua Brindle. + +1.3.23 2005-10-18 + * Changed default args for load_policy to be null, as it no longer + takes a pathname argument and we want to preserve booleans. + +1.3.22 2005-10-18 + * Merged move local dbase initialization patch from Ivan Gyurdiev. + * Merged acquire/release read lock in databases patch from Ivan Gyurdiev. + * Merged rename direct -> policydb as appropriate patch from Ivan Gyurdiev. + +1.3.21 2005-10-18 + * Added calls to sepol_policy_file_set_handle interface prior + to invoking sepol operations on policy files. + * Updated call to sepol_policydb_from_image to pass the handle. + +1.3.20 2005-10-17 + * Merged user and port APIs - policy database patch from Ivan + Gyurdiev. + +1.3.19 2005-10-17 + * Converted calls to sepol link_packages and expand_module interfaces + from using buffers to using sepol handles for error reporting, and + changed direct_connect/disconnect to create/destroy sepol handles. + +1.3.18 2005-10-14 + * Merged bugfix patch from Ivan Gyurdiev. + +1.3.17 2005-10-14 + * Merged seuser database patch from Ivan Gyurdiev. + Merged direct user/port databases to the handle from Ivan Gyurdiev. + +1.3.16 2005-10-14 + * Removed obsolete include/semanage/commit_api.h (leftover). + Merged seuser record patch from Ivan Gyurdiev. + +1.3.15 2005-10-14 + * Merged boolean and interface databases from Ivan Gyurdiev. + +1.3.14 2005-10-13 + * Updated to use get interfaces for hidden sepol_module_package type. + +1.3.13 2005-10-13 + * Changed semanage_expand_sandbox and semanage_install_active + to generate/install the latest policy version supported by libsepol + by default (unless overridden by semanage.conf), since libselinux + will now downgrade automatically for load_policy. + +1.3.12 2005-10-13 + * Merged new callback-based error reporting system and ongoing + database work from Ivan Gyurdiev. + +1.3.11 2005-10-11 + * Fixed semanage_install_active() to use the same logic for + selecting a policy version as semanage_expand_sandbox(). Dropped + dead code from semanage_install_sandbox(). + +1.3.10 2005-10-07 + * Updated for changes to libsepol, and to only use types and interfaces + provided by the shared libsepol. + +1.3.9 2005-10-06 + * Merged further database work from Ivan Gyurdiev. + +1.3.8 2005-10-04 + * Merged iterate, redistribute, and dbase split patches from + Ivan Gyurdiev. + +1.3.7 2005-09-30 + * Merged patch series from Ivan Gyurdiev. + (pointer typedef elimination, file renames, dbase work, backend + separation) + +1.3.6 2005-09-28 + * Split interfaces from semanage.[hc] into handle.[hc], modules.[hc]. + * Separated handle create from connect interface. + * Added a constructor for initialization. + * Moved up src/include/*.h to src. + * Created a symbol map file; dropped dso.h and hidden markings. + +1.3.5 2005-09-28 + * Merged major update to libsemanage organization and functionality + from Karl MacMillan (Tresys). + +1.3.4 2005-09-23 + * Merged dbase redesign patch from Ivan Gyurdiev. + +1.3.3 2005-09-21 + * Merged boolean record, stub record handler, and status codes + patches from Ivan Gyurdiev. + +1.3.2 2005-09-16 + * Merged stub iterator functionality from Ivan Gyurdiev. + * Merged interface record patch from Ivan Gyurdiev. + +1.3.1 2005-09-14 + * Merged stub functionality for managing user and port records, + and record table code from Ivan Gyurdiev. + +1.2 2005-09-06 + * Updated version for release. + +1.1.6 2005-08-31 + * Merged semod.conf template patch from Dan Walsh (Red Hat), + but restored location to /usr/share/semod/semod.conf. + +1.1.5 2005-08-30 + * Fixed several bugs found by valgrind. + * Fixed bug in prior patch for the semod_build_module_list leak. + +1.1.4 2005-08-25 + * Merged errno fix from Joshua Brindle (Tresys). + * Merged fix for semod_build_modules_list leak on error path + from Serge Hallyn (IBM). Bug found by Coverity. + +1.1.3 2005-08-22 + * Merged several fixes from Serge Hallyn (IBM). Bugs found by + Coverity. + * Fixed several other bugs and warnings. + +1.1.2 2005-08-02 + * Merged patch to move module read/write code from libsemanage + to libsepol from Jason Tang (Tresys). + +1.1.1 2005-08-02 + * Merged relay records patch from Ivan Gyurdiev. + * Merged key extract patch from Ivan Gyurdiev. + +1.0 2005-07-27 + * Initial version.
diff --git a/selinux/libsemanage/Makefile b/selinux/libsemanage/Makefile new file mode 100644 index 0000000..390176f --- /dev/null +++ b/selinux/libsemanage/Makefile
@@ -0,0 +1,37 @@ +all: + $(MAKE) -C src all + +swigify: + $(MAKE) -C src swigify + +pywrap: + $(MAKE) -C src pywrap + +rubywrap: + $(MAKE) -C src rubywrap + +install: + $(MAKE) -C include install + $(MAKE) -C src install + $(MAKE) -C man install + $(MAKE) -C utils install + +install-pywrap: + $(MAKE) -C src install-pywrap + +install-rubywrap: + $(MAKE) -C src install-rubywrap + +relabel: + $(MAKE) -C src relabel + +clean distclean: + $(MAKE) -C src $@ + $(MAKE) -C tests $@ + +indent: + $(MAKE) -C src $@ + $(MAKE) -C include $@ + +test: all + $(MAKE) -C tests test
diff --git a/selinux/libsemanage/VERSION b/selinux/libsemanage/VERSION new file mode 100644 index 0000000..95e3ba8 --- /dev/null +++ b/selinux/libsemanage/VERSION
@@ -0,0 +1 @@ +2.5
diff --git a/selinux/libsemanage/example/test_fcontext.c b/selinux/libsemanage/example/test_fcontext.c new file mode 100644 index 0000000..c2ffcab --- /dev/null +++ b/selinux/libsemanage/example/test_fcontext.c
@@ -0,0 +1,72 @@ +#include <semanage/fcontext_record.h> +#include <semanage/semanage.h> +#include <semanage/fcontexts_local.h> +#include <sepol/sepol.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +int main(const int argc, const char **argv) { + semanage_handle_t *sh = NULL; + semanage_fcontext_t *fcontext; + semanage_context_t *con; + semanage_fcontext_key_t *k; + + int exist = 0; + sh = semanage_handle_create(); + if (sh == NULL) { + perror("Can't create semanage handle\n"); + return -1; + } + if (semanage_access_check(sh) < 0) { + perror("Semanage access check failed\n"); + return -1; + } + if (semanage_connect(sh) < 0) { + perror("Semanage connect failed\n"); + return -1; + } + + if (semanage_fcontext_key_create(sh, argv[2], SEMANAGE_FCONTEXT_REG, &k) < 0) { + fprintf(stderr, "Could not create key for %s", argv[2]); + return -1; + } + + if(semanage_fcontext_exists(sh, k, &exist) < 0) { + fprintf(stderr,"Could not check if key exists for %s", argv[2]); + return -1; + } + if (exist) { + fprintf(stderr,"Could create %s mapping already exists", argv[2]); + return -1; + } + + if (semanage_fcontext_create(sh, &fcontext) < 0) { + fprintf(stderr,"Could not create file context for %s", argv[2]); + return -1; + } + semanage_fcontext_set_expr(sh, fcontext, argv[2]); + + if (semanage_context_from_string(sh, argv[1], &con)) { + fprintf(stderr,"Could not create context using %s for file context %s", argv[1], argv[2]); + return -1; + } + + if (semanage_fcontext_set_con(sh, fcontext, con) < 0) { + fprintf(stderr,"Could not set file context for %s", argv[2]); + return -1; + } + + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_REG); + + if(semanage_fcontext_modify_local(sh, k, fcontext) < 0) { + fprintf(stderr,"Could not add file context for %s", argv[2]); + return -1; + } + semanage_fcontext_key_free(k); + semanage_fcontext_free(fcontext); + + return 0; +} +
diff --git a/selinux/libsemanage/include/Makefile b/selinux/libsemanage/include/Makefile new file mode 100644 index 0000000..b660660 --- /dev/null +++ b/selinux/libsemanage/include/Makefile
@@ -0,0 +1,12 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +INCDIR ?= $(PREFIX)/include/semanage + +all: + +install: all + test -d $(INCDIR) || install -m 755 -d $(INCDIR) + install -m 644 $(wildcard semanage/*.h) $(INCDIR) + +indent: + ../../scripts/Lindent $(wildcard semanage/*.h)
diff --git a/selinux/libsemanage/include/semanage/boolean_record.h b/selinux/libsemanage/include/semanage/boolean_record.h new file mode 100644 index 0000000..b618593 --- /dev/null +++ b/selinux/libsemanage/include/semanage/boolean_record.h
@@ -0,0 +1,54 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_BOOLEAN_RECORD_H_ +#define _SEMANAGE_BOOLEAN_RECORD_H_ + +#include <semanage/handle.h> + +#ifndef _SEMANAGE_BOOL_DEFINED_ +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool semanage_bool_t; +typedef struct semanage_bool_key semanage_bool_key_t; +#define _SEMANAGE_BOOL_DEFINED_ +#endif + +/* Key */ +extern int semanage_bool_key_create(semanage_handle_t * handle, + const char *name, + semanage_bool_key_t ** key); + +extern int semanage_bool_key_extract(semanage_handle_t * handle, + const semanage_bool_t * boolean, + semanage_bool_key_t ** key); + +extern void semanage_bool_key_free(semanage_bool_key_t * key); + +extern int semanage_bool_compare(const semanage_bool_t * boolean, + const semanage_bool_key_t * key); + +extern int semanage_bool_compare2(const semanage_bool_t * boolean, + const semanage_bool_t * boolean2); + +/* Name */ +extern const char *semanage_bool_get_name(const semanage_bool_t * boolean); + +extern int semanage_bool_set_name(semanage_handle_t * handle, + semanage_bool_t * boolean, const char *name); + +/* Value */ +extern int semanage_bool_get_value(const semanage_bool_t * boolean); + +extern void semanage_bool_set_value(semanage_bool_t * boolean, int value); + +/* Create/Clone/Destroy */ +extern int semanage_bool_create(semanage_handle_t * handle, + semanage_bool_t ** bool_ptr); + +extern int semanage_bool_clone(semanage_handle_t * handle, + const semanage_bool_t * boolean, + semanage_bool_t ** bool_ptr); + +extern void semanage_bool_free(semanage_bool_t * boolean); + +#endif
diff --git a/selinux/libsemanage/include/semanage/booleans_active.h b/selinux/libsemanage/include/semanage/booleans_active.h new file mode 100644 index 0000000..0bbe51b --- /dev/null +++ b/selinux/libsemanage/include/semanage/booleans_active.h
@@ -0,0 +1,33 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_BOOLEANS_ACTIVE_H_ +#define _SEMANAGE_BOOLEANS_ACTIVE_H_ + +#include <semanage/boolean_record.h> +#include <semanage/handle.h> + +extern int semanage_bool_set_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, + const semanage_bool_t * data); + +extern int semanage_bool_query_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response); + +extern int semanage_bool_exists_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, + int *response); + +extern int semanage_bool_count_active(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_bool_iterate_active(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * + record, void *varg), + void *handler_arg); + +extern int semanage_bool_list_active(semanage_handle_t * handle, + semanage_bool_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/booleans_local.h b/selinux/libsemanage/include/semanage/booleans_local.h new file mode 100644 index 0000000..a32e98c --- /dev/null +++ b/selinux/libsemanage/include/semanage/booleans_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_BOOLEANS_LOCAL_H_ +#define _SEMANAGE_BOOLEANS_LOCAL_H_ + +#include <semanage/boolean_record.h> +#include <semanage/handle.h> + +extern int semanage_bool_modify_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, + const semanage_bool_t * data); + +extern int semanage_bool_del_local(semanage_handle_t * handle, + const semanage_bool_key_t * key); + +extern int semanage_bool_query_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response); + +extern int semanage_bool_exists_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, + int *response); + +extern int semanage_bool_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_bool_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * + record, void *varg), + void *handler_arg); + +extern int semanage_bool_list_local(semanage_handle_t * handle, + semanage_bool_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/booleans_policy.h b/selinux/libsemanage/include/semanage/booleans_policy.h new file mode 100644 index 0000000..08d0bbb --- /dev/null +++ b/selinux/libsemanage/include/semanage/booleans_policy.h
@@ -0,0 +1,27 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_BOOLEANS_POLICY_H_ +#define _SEMANAGE_BOOLEANS_POLICY_H_ + +#include <semanage/handle.h> +#include <semanage/boolean_record.h> + +extern int semanage_bool_query(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response); + +extern int semanage_bool_exists(semanage_handle_t * handle, + const semanage_bool_key_t * key, int *response); + +extern int semanage_bool_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_bool_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * record, + void *varg), + void *handler_arg); + +extern int semanage_bool_list(semanage_handle_t * handle, + semanage_bool_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/context_record.h b/selinux/libsemanage/include/semanage/context_record.h new file mode 100644 index 0000000..54dcea5 --- /dev/null +++ b/selinux/libsemanage/include/semanage/context_record.h
@@ -0,0 +1,61 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_CONTEXT_RECORD_H_ +#define _SEMANAGE_CONTEXT_RECORD_H_ + +#include <semanage/handle.h> + +#ifndef _SEMANAGE_CONTEXT_DEFINED_ +struct semanage_context; +typedef struct semanage_context semanage_context_t; +#define _SEMANAGE_CONTEXT_DEFINED_ +#endif + +/* User */ +extern const char *semanage_context_get_user(const semanage_context_t * con); + +extern int semanage_context_set_user(semanage_handle_t * handle, + semanage_context_t * con, + const char *user); + +/* Role */ +extern const char *semanage_context_get_role(const semanage_context_t * con); + +extern int semanage_context_set_role(semanage_handle_t * handle, + semanage_context_t * con, + const char *role); + +/* Type */ +extern const char *semanage_context_get_type(const semanage_context_t * con); + +extern int semanage_context_set_type(semanage_handle_t * handle, + semanage_context_t * con, + const char *type); + +/* MLS */ +extern const char *semanage_context_get_mls(const semanage_context_t * con); + +extern int semanage_context_set_mls(semanage_handle_t * handle, + semanage_context_t * con, + const char *mls_range); + +/* Create/Clone/Destroy */ +extern int semanage_context_create(semanage_handle_t * handle, + semanage_context_t ** con_ptr); + +extern int semanage_context_clone(semanage_handle_t * handle, + const semanage_context_t * con, + semanage_context_t ** con_ptr); + +extern void semanage_context_free(semanage_context_t * con); + +/* Parse to/from string */ +extern int semanage_context_from_string(semanage_handle_t * handle, + const char *str, + semanage_context_t ** con); + +extern int semanage_context_to_string(semanage_handle_t * handle, + const semanage_context_t * con, + char **str_ptr); + +#endif
diff --git a/selinux/libsemanage/include/semanage/debug.h b/selinux/libsemanage/include/semanage/debug.h new file mode 100644 index 0000000..effc24a --- /dev/null +++ b/selinux/libsemanage/include/semanage/debug.h
@@ -0,0 +1,54 @@ +/* Author: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Ivan Gyurdiev <ivg2@cornell.edu> + * + * Copyright (C) 2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_DEBUG_H_ +#define _SEMANAGE_DEBUG_H_ + +#include <semanage/handle.h> + +#define SEMANAGE_MSG_ERR 1 +#define SEMANAGE_MSG_WARN 2 +#define SEMANAGE_MSG_INFO 3 + +extern int semanage_msg_get_level(semanage_handle_t * handle); + +extern const char *semanage_msg_get_channel(semanage_handle_t * handle); + +extern const char *semanage_msg_get_fname(semanage_handle_t * handle); + +/* Set the messaging callback. + * By the default, the callback will print + * the message on standard output, in a + * particular format. Passing NULL here + * indicates that messaging should be suppressed */ +extern void semanage_msg_set_callback(semanage_handle_t * handle, +#ifdef __GNUC__ + __attribute__ ((format(printf, 3, 4))) +#endif + void (*msg_callback) (void *varg, + semanage_handle_t * + handle, + const char *fmt, + ...), + void *msg_callback_arg); + +#endif
diff --git a/selinux/libsemanage/include/semanage/fcontext_record.h b/selinux/libsemanage/include/semanage/fcontext_record.h new file mode 100644 index 0000000..4cf9261 --- /dev/null +++ b/selinux/libsemanage/include/semanage/fcontext_record.h
@@ -0,0 +1,78 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_FCONTEXT_RECORD_H_ +#define _SEMANAGE_FCONTEXT_RECORD_H_ + +#include <semanage/context_record.h> +#include <semanage/handle.h> + +#ifndef _SEMANAGE_FCONTEXT_DEFINED_ +struct semanage_fcontext; +struct semanage_fcontext_key; +typedef struct semanage_fcontext semanage_fcontext_t; +typedef struct semanage_fcontext_key semanage_fcontext_key_t; +#define _SEMANAGE_FCONTEXT_DEFINED_ +#endif + +/* Key */ +extern int semanage_fcontext_compare(const semanage_fcontext_t * fcontext, + const semanage_fcontext_key_t * key); + +extern int semanage_fcontext_compare2(const semanage_fcontext_t * fcontext, + const semanage_fcontext_t * fcontext2); + +extern int semanage_fcontext_key_create(semanage_handle_t * handle, + const char *expr, + int type, + semanage_fcontext_key_t ** key_ptr); + +extern int semanage_fcontext_key_extract(semanage_handle_t * handle, + const semanage_fcontext_t * fcontext, + semanage_fcontext_key_t ** key_ptr); + +extern void semanage_fcontext_key_free(semanage_fcontext_key_t * key); + +/* Regexp */ +extern const char *semanage_fcontext_get_expr(const semanage_fcontext_t * + fcontext); + +extern int semanage_fcontext_set_expr(semanage_handle_t * handle, + semanage_fcontext_t * fcontext, + const char *expr); + +/* Type */ +#define SEMANAGE_FCONTEXT_ALL 0 +#define SEMANAGE_FCONTEXT_REG 1 +#define SEMANAGE_FCONTEXT_DIR 2 +#define SEMANAGE_FCONTEXT_CHAR 3 +#define SEMANAGE_FCONTEXT_BLOCK 4 +#define SEMANAGE_FCONTEXT_SOCK 5 +#define SEMANAGE_FCONTEXT_LINK 6 +#define SEMANAGE_FCONTEXT_PIPE 7 + +extern int semanage_fcontext_get_type(const semanage_fcontext_t * fcontext); + +extern const char *semanage_fcontext_get_type_str(int type); + +extern void semanage_fcontext_set_type(semanage_fcontext_t * fcontext, + int type); + +/* Context */ +extern semanage_context_t *semanage_fcontext_get_con(const semanage_fcontext_t * + fcontext); + +extern int semanage_fcontext_set_con(semanage_handle_t * handle, + semanage_fcontext_t * fcontext, + semanage_context_t * con); + +/* Create/Clone/Destroy */ +extern int semanage_fcontext_create(semanage_handle_t * handle, + semanage_fcontext_t ** fcontext_ptr); + +extern int semanage_fcontext_clone(semanage_handle_t * handle, + const semanage_fcontext_t * fcontext, + semanage_fcontext_t ** fcontext_ptr); + +extern void semanage_fcontext_free(semanage_fcontext_t * fcontext); + +#endif
diff --git a/selinux/libsemanage/include/semanage/fcontexts_local.h b/selinux/libsemanage/include/semanage/fcontexts_local.h new file mode 100644 index 0000000..aaecc0f --- /dev/null +++ b/selinux/libsemanage/include/semanage/fcontexts_local.h
@@ -0,0 +1,37 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_FCONTEXTS_LOCAL_H_ +#define _SEMANAGE_FCONTEXTS_LOCAL_H_ + +#include <semanage/fcontext_record.h> +#include <semanage/handle.h> + +extern int semanage_fcontext_modify_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + const semanage_fcontext_t * data); + +extern int semanage_fcontext_del_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key); + +extern int semanage_fcontext_query_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + semanage_fcontext_t ** response); + +extern int semanage_fcontext_exists_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + int *response); + +extern int semanage_fcontext_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_fcontext_iterate_local(semanage_handle_t * handle, + int (*handler) (const + semanage_fcontext_t * + record, void *varg), + void *handler_arg); + +extern int semanage_fcontext_list_local(semanage_handle_t * handle, + semanage_fcontext_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/fcontexts_policy.h b/selinux/libsemanage/include/semanage/fcontexts_policy.h new file mode 100644 index 0000000..a50db2b --- /dev/null +++ b/selinux/libsemanage/include/semanage/fcontexts_policy.h
@@ -0,0 +1,29 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_FCONTEXTS_POLICY_H_ +#define _SEMANAGE_FCONTEXTS_POLICY_H_ + +#include <semanage/fcontext_record.h> +#include <semanage/handle.h> + +extern int semanage_fcontext_query(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + semanage_fcontext_t ** response); + +extern int semanage_fcontext_exists(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + int *response); + +extern int semanage_fcontext_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_fcontext_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_fcontext_t * + record, void *varg), + void *handler_arg); + +extern int semanage_fcontext_list(semanage_handle_t * handle, + semanage_fcontext_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/handle.h b/selinux/libsemanage/include/semanage/handle.h new file mode 100644 index 0000000..c816590 --- /dev/null +++ b/selinux/libsemanage/include/semanage/handle.h
@@ -0,0 +1,172 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2005 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_HANDLE_H_ +#define _SEMANAGE_HANDLE_H_ + +#include <stdint.h> + +/* All accesses with semanage are through a "semanage_handle". The + * handle may ultimately reference local config files, + * the binary policy file, a module store, or a policy management server. + */ +struct semanage_handle; +typedef struct semanage_handle semanage_handle_t; + +/* Create and return a semanage handle. + The handle is initially in the disconnected state. */ +semanage_handle_t *semanage_handle_create(void); + +/* Deallocate all space associated with a semanage_handle_t, including + * the pointer itself. CAUTION: this function does not disconnect + * from the backend; be sure that a semanage_disconnect() was + * previously called if the handle was connected. */ +void semanage_handle_destroy(semanage_handle_t *); + +/* This is the type of connection to the store, for now only + * direct is supported */ +enum semanage_connect_type { + SEMANAGE_CON_INVALID = 0, SEMANAGE_CON_DIRECT, + SEMANAGE_CON_POLSERV_LOCAL, SEMANAGE_CON_POLSERV_REMOTE +}; + +/* This function allows you to specify the store to connect to. + * It must be called after semanage_handle_create but before + * semanage_connect. The argument should be the full path to the store. + */ +void semanage_select_store(semanage_handle_t * handle, char *path, + enum semanage_connect_type storetype); + +/* Just reload the policy */ +int semanage_reload_policy(semanage_handle_t * handle); + +/* set whether to reload the policy or not after a commit, + * 1 for yes (default), 0 for no */ +void semanage_set_reload(semanage_handle_t * handle, int do_reload); + +/* set whether to rebuild the policy on commit, even if no + * changes were performed. + * 1 for yes, 0 for no (default) */ +void semanage_set_rebuild(semanage_handle_t * handle, int do_rebuild); + +/* Fills *compiler_path with the location of the hll compiler sh->conf->compiler_directory_path + * corresponding to lang_ext. + * Upon success returns 0, -1 on error. */ +int semanage_get_hll_compiler_path(semanage_handle_t *sh, char *lang_ext, char **compiler_path); + +/* create the store if it does not exist, this only has an effect on + * direct connections and must be called before semanage_connect + * 1 for yes, 0 for no (default) */ +void semanage_set_create_store(semanage_handle_t * handle, int create_store); + +/*Get whether or not dontaudits will be disabled upon commit */ +int semanage_get_disable_dontaudit(semanage_handle_t * handle); + +/* Set whether or not to disable dontaudits upon commit */ +void semanage_set_disable_dontaudit(semanage_handle_t * handle, int disable_dontaudit); + +/* Set whether or not to execute setfiles to check file contexts upon commit */ +void semanage_set_check_contexts(semanage_handle_t * sh, int do_check_contexts); + +/* Get the default priority. */ +uint16_t semanage_get_default_priority(semanage_handle_t *sh); + +/* Set the default priority. */ +int semanage_set_default_priority(semanage_handle_t *sh, uint16_t priority); + +/* Check whether policy is managed via libsemanage on this system. + * Must be called prior to trying to connect. + * Return 1 if policy is managed via libsemanage on this system, + * 0 if policy is not managed, or -1 on error. + */ +int semanage_is_managed(semanage_handle_t *); + +/* "Connect" to a manager based on the configuration and + * associate the provided handle with the connection. + * If the connect fails then this function returns a negative value, + * else it returns zero. + */ +int semanage_connect(semanage_handle_t *); + +/* Disconnect from the manager given by the handle. If already + * disconnected then this function does nothing. Return 0 if + * disconnected properly or already disconnected, negative value on + * error. */ +int semanage_disconnect(semanage_handle_t *); + +/* Attempt to obtain a transaction lock on the manager. If another + * process has the lock then this function may block, depending upon + * the timeout value in the handle. + * + * Note that if the semanage_handle has not yet obtained a transaction + * lock whenever a writer function is called, there will be an + * implicit call to this function. */ +int semanage_begin_transaction(semanage_handle_t *); + +/* Attempt to commit all changes since this transaction began. If the + * commit is successful then increment the "policy sequence number" + * and then release the transaction lock. Return that policy number + * afterwards, or -1 on error. + */ +int semanage_commit(semanage_handle_t *); + +#define SEMANAGE_CAN_READ 1 +#define SEMANAGE_CAN_WRITE 2 +/* returns SEMANAGE_CAN_READ or SEMANAGE_CAN_WRITE if the store is readable + * or writable, respectively. <0 if an error occurred */ +int semanage_access_check(semanage_handle_t * sh); + +/* returns 0 if not connected, 1 if connected */ +int semanage_is_connected(semanage_handle_t * sh); + +/* returns 1 if policy is MLS, 0 otherwise. */ +int semanage_mls_enabled(semanage_handle_t *sh); + +/* Change to alternate semanage root path */ +int semanage_set_root(const char *path); + +/* Get the current semanage root path */ +const char * semanage_root(void); + +/* Get whether or not needless unused branch of tunables would be preserved */ +int semanage_get_preserve_tunables(semanage_handle_t * handle); + +/* Set whether or not to preserve the needless unused branch of tunables */ +void semanage_set_preserve_tunables(semanage_handle_t * handle, int preserve_tunables); + +/* Get the flag value for whether or not caching is ignored for compiled CIL modules from HLL files */ +int semanage_get_ignore_module_cache(semanage_handle_t *handle); + +/* Set semanage_handle flag for whether or not to ignore caching of compiled CIL modules from HLL files */ +void semanage_set_ignore_module_cache(semanage_handle_t *handle, int ignore_module_cache); + +/* set the store root path for semanage output files */ +void semanage_set_store_root(semanage_handle_t *sh, const char *store_root); + +/* META NOTES + * + * For all functions a non-negative number indicates success. For some + * functions a >=0 returned value is the "policy sequence number". This + * number keeps tracks of policy revisions and is used to detect if + * one semanage client has committed policy changes while another is + * still connected. + */ + +#endif
diff --git a/selinux/libsemanage/include/semanage/iface_record.h b/selinux/libsemanage/include/semanage/iface_record.h new file mode 100644 index 0000000..857d42e --- /dev/null +++ b/selinux/libsemanage/include/semanage/iface_record.h
@@ -0,0 +1,65 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_IFACE_RECORD_H_ +#define _SEMANAGE_IFACE_RECORD_H_ + +#include <semanage/context_record.h> +#include <semanage/handle.h> + +#ifndef _SEMANAGE_IFACE_DEFINED_ +struct semanage_iface; +struct semanage_iface_key; +typedef struct semanage_iface semanage_iface_t; +typedef struct semanage_iface_key semanage_iface_key_t; +#define _SEMANAGE_IFACE_DEFINED_ +#endif + +/* Key */ +extern int semanage_iface_compare(const semanage_iface_t * iface, + const semanage_iface_key_t * key); + +extern int semanage_iface_compare2(const semanage_iface_t * iface, + const semanage_iface_t * iface2); + +extern int semanage_iface_key_create(semanage_handle_t * handle, + const char *name, + semanage_iface_key_t ** key_ptr); + +extern int semanage_iface_key_extract(semanage_handle_t * handle, + const semanage_iface_t * iface, + semanage_iface_key_t ** key_ptr); + +extern void semanage_iface_key_free(semanage_iface_key_t * key); + +/* Name */ +extern const char *semanage_iface_get_name(const semanage_iface_t * iface); + +extern int semanage_iface_set_name(semanage_handle_t * handle, + semanage_iface_t * iface, const char *name); + +/* Context */ +extern semanage_context_t *semanage_iface_get_ifcon(const semanage_iface_t * + iface); + +extern int semanage_iface_set_ifcon(semanage_handle_t * handle, + semanage_iface_t * iface, + semanage_context_t * con); + +extern semanage_context_t *semanage_iface_get_msgcon(const semanage_iface_t * + iface); + +extern int semanage_iface_set_msgcon(semanage_handle_t * handle, + semanage_iface_t * iface, + semanage_context_t * con); + +/* Create/Clone/Destroy */ +extern int semanage_iface_create(semanage_handle_t * handle, + semanage_iface_t ** iface_ptr); + +extern int semanage_iface_clone(semanage_handle_t * handle, + const semanage_iface_t * iface, + semanage_iface_t ** iface_ptr); + +extern void semanage_iface_free(semanage_iface_t * iface); + +#endif
diff --git a/selinux/libsemanage/include/semanage/interfaces_local.h b/selinux/libsemanage/include/semanage/interfaces_local.h new file mode 100644 index 0000000..9b07ca6 --- /dev/null +++ b/selinux/libsemanage/include/semanage/interfaces_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_INTERFACES_LOCAL_H_ +#define _SEMANAGE_INTERFACES_LOCAL_H_ + +#include <semanage/iface_record.h> +#include <semanage/handle.h> + +extern int semanage_iface_modify_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, + const semanage_iface_t * data); + +extern int semanage_iface_del_local(semanage_handle_t * handle, + const semanage_iface_key_t * key); + +extern int semanage_iface_query_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, + semanage_iface_t ** response); + +extern int semanage_iface_exists_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, + int *response); + +extern int semanage_iface_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_iface_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_iface_t * + record, void *varg), + void *handler_arg); + +extern int semanage_iface_list_local(semanage_handle_t * handle, + semanage_iface_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/interfaces_policy.h b/selinux/libsemanage/include/semanage/interfaces_policy.h new file mode 100644 index 0000000..9816280 --- /dev/null +++ b/selinux/libsemanage/include/semanage/interfaces_policy.h
@@ -0,0 +1,29 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_INTERFACES_POLICY_H_ +#define _SEMANAGE_INTERFACES_POLICY_H_ + +#include <semanage/handle.h> +#include <semanage/iface_record.h> + +extern int semanage_iface_query(semanage_handle_t * handle, + const semanage_iface_key_t * key, + semanage_iface_t ** response); + +extern int semanage_iface_exists(semanage_handle_t * handle, + const semanage_iface_key_t * key, + int *response); + +extern int semanage_iface_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_iface_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_iface_t * + record, void *varg), + void *handler_arg); + +extern int semanage_iface_list(semanage_handle_t * handle, + semanage_iface_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/modules.h b/selinux/libsemanage/include/semanage/modules.h new file mode 100644 index 0000000..4b93e54 --- /dev/null +++ b/selinux/libsemanage/include/semanage/modules.h
@@ -0,0 +1,285 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2005 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_MODULES_H_ +#define _SEMANAGE_MODULES_H_ + +#include <stddef.h> +#include <stdint.h> +#include <semanage/handle.h> +#include <sys/types.h> + +typedef struct semanage_module_key semanage_module_key_t; + +/* High level module management functions. These are all part of + * a transaction + */ + +int semanage_module_install(semanage_handle_t *, + char *module_data, size_t data_len, char *name, char *ext_lang); +int semanage_module_install_file(semanage_handle_t *, + const char *module_name); +int semanage_module_remove(semanage_handle_t *, char *module_name); + +/* semanage_module_info is for getting information on installed + modules, only name at this time */ +typedef struct semanage_module_info semanage_module_info_t; + +/* Look up a module using @modkey. The module's raw data is returned as a + * @mapped_data blob and size of the mapped_data is returned as @data_len. + * @modinfo contains additional information which can be used by the caller such + * as the high level language extension of @mapped_data. + * + * On success, the caller is responsible for unmapping @mapped_data with munmap(), + * destroying @modinfo with semanage_module_info_destroy(), and freeing @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_extract(semanage_handle_t *sh, + semanage_module_key_t *modkey, + int extract_cil, + void **mapped_data, + size_t *data_len, + semanage_module_info_t **modinfo); +int semanage_module_list(semanage_handle_t *, + semanage_module_info_t **, int *num_modules); +void semanage_module_info_datum_destroy(semanage_module_info_t *); +semanage_module_info_t *semanage_module_list_nth(semanage_module_info_t * list, + int n); +const char *semanage_module_get_name(semanage_module_info_t *); + +/* Module Info */ + +/* Creates a module info struct. + * + * Returns 0 on success and -1 on failure. + * + * The @modinfo should be destroyed with semanage_module_info_destroy. + * The caller should call free() on the struct. + */ +int semanage_module_info_create(semanage_handle_t *sh, + semanage_module_info_t **modinfo); + +/* Frees the members of the module info struct. + * + * Returns 0 on success and -1 on failure. + * + * The caller should call free() on the struct. + */ +int semanage_module_info_destroy(semanage_handle_t *handle, + semanage_module_info_t *modinfo); + +/* Module Info Getters */ + +/* Get @priority from @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_get_priority(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + uint16_t *priority); + +/* Get @name from @modinfo. Caller should not free @name. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_get_name(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char **name); + +/* Get @lang_ext from @modinfo. Caller should not free @lang_ext. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_get_lang_ext(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char **lang_ext); + +/* Get @enabled from @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_get_enabled(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + int *enabled); + +/* Module Info Setters */ + +/* Set @priority in @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_set_priority(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + uint16_t priority); + +/* Set @name in @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_set_name(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char *name); + +/* Set @lang_ext in @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_set_lang_ext(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char *lang_ext); + +/* Set @enabled in @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_set_enabled(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + int enabled); + +/* Module Key */ + +/* Creates a module key struct. + * + * Return 0 on success, and -1 on error. + * + * The @modkey should be destroyed with semanage_module_key_destroy. + * The caller should call free() on the struct. + */ +int semanage_module_key_create(semanage_handle_t *sh, + semanage_module_key_t **modkey); + +/* Frees members of the @modkey, but not the struct. The caller should + * call free() on struct. + * + * Returns 0 on success, and -1 on error. + */ +int semanage_module_key_destroy(semanage_handle_t *sh, + semanage_module_key_t *modkey); + +/* Module Key Getters */ + +/* Get @name from @modkey. Caller should not free @name. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_key_get_name(semanage_handle_t *sh, + semanage_module_key_t *modkey, + const char **name); + +/* Get @name from @modkey. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_key_get_priority(semanage_handle_t *sh, + semanage_module_key_t *modkey, + uint16_t *priority); + +/* Module Key Setters */ + +/* Set @name in @modkey. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_key_set_name(semanage_handle_t *sh, + semanage_module_key_t *modkey, + const char *name); + +/* Set @priority in @modkey. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_key_set_priority(semanage_handle_t *sh, + semanage_module_key_t *modkey, + uint16_t priority); + +/* Set module @enabled status from @modkey. Modules are enabled on a per + * module name basis (across all priorities). @modkey only needs to have + * name set (priority is ignored). + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_set_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int enabled); + +/* Lookup @modinfo by @modkey. Caller should use + * semanage_module_info_destroy and free on @modinfo. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_get_module_info(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + semanage_module_info_t **modinfo); + +/* Create a list of all modules in @modinfos of length @modinfos_len. + * The list will be sorted from high priority to low and alphabetically + * by module name within a priority. + * + * Caller should use semanage_module_info_destroy on each modinfo in + * @modinfos and free on @modinfos. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_list_all(semanage_handle_t *sh, + semanage_module_info_t **modinfos, + int *modinfos_len); + +/* Install the module indicated by @modinfo with input data from + * @module_data with length @data_len. + * + * @modinfo must have all values filled in. + * @module_data may be bzip compressed. + * + * Returns: + * 0 success + * -1 failure, out of memory + * -2 failure, invalid @modinfo + * -3 failure, error writing file + */ +int semanage_module_install_info(semanage_handle_t *sh, + const semanage_module_info_t *modinfo, + char *data, + size_t data_len); + +/* Remove the module indicated by @modkey. + * @modkey must have key values filled in. + * + * Returns: + * 0 success + * -1 failure, out of memeory + * -2 failure, @module not found or couldn't be removed + */ +int semanage_module_remove_key(semanage_handle_t *sh, + const semanage_module_key_t *modkey); + +/* Module Enabled */ + +/* Get module @enabled status from @modkey. Modules are enabled on a per + * module name basis (across all priorities). @modkey only needs to have + * name set (priority is ignored). + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_get_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int *enabled); + +#endif
diff --git a/selinux/libsemanage/include/semanage/node_record.h b/selinux/libsemanage/include/semanage/node_record.h new file mode 100644 index 0000000..c9e4ce8 --- /dev/null +++ b/selinux/libsemanage/include/semanage/node_record.h
@@ -0,0 +1,95 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_NODE_RECORD_H_ +#define _SEMANAGE_NODE_RECORD_H_ + +#include <semanage/context_record.h> +#include <semanage/handle.h> +#include <stddef.h> + +#ifndef _SEMANAGE_NODE_DEFINED_ +struct semanage_node; +struct semanage_node_key; +typedef struct semanage_node semanage_node_t; +typedef struct semanage_node_key semanage_node_key_t; +#define _SEMANAGE_NODE_DEFINED_ +#endif + +#define SEMANAGE_PROTO_IP4 0 +#define SEMANAGE_PROTO_IP6 1 + +/* Key */ +extern int semanage_node_compare(const semanage_node_t * node, + const semanage_node_key_t * key); + +extern int semanage_node_compare2(const semanage_node_t * node, + const semanage_node_t * node2); + +extern int semanage_node_key_create(semanage_handle_t * handle, + const char *addr, + const char *mask, + int proto, semanage_node_key_t ** key_ptr); + +extern int semanage_node_key_extract(semanage_handle_t * handle, + const semanage_node_t * node, + semanage_node_key_t ** key_ptr); + +extern void semanage_node_key_free(semanage_node_key_t * key); + +/* Address */ +extern int semanage_node_get_addr(semanage_handle_t * handle, + const semanage_node_t * node, char **addr); + +extern int semanage_node_get_addr_bytes(semanage_handle_t * handle, + const semanage_node_t * node, + char **addr, size_t * addr_sz); + +extern int semanage_node_set_addr(semanage_handle_t * handle, + semanage_node_t * node, + int proto, const char *addr); + +extern int semanage_node_set_addr_bytes(semanage_handle_t * handle, + semanage_node_t * node, + const char *addr, size_t addr_sz); + +/* Netmask */ +extern int semanage_node_get_mask(semanage_handle_t * handle, + const semanage_node_t * node, char **mask); + +extern int semanage_node_get_mask_bytes(semanage_handle_t * handle, + const semanage_node_t * node, + char **mask, size_t * mask_sz); + +extern int semanage_node_set_mask(semanage_handle_t * handle, + semanage_node_t * node, + int proto, const char *mask); + +extern int semanage_node_set_mask_bytes(semanage_handle_t * handle, + semanage_node_t * node, + const char *mask, size_t mask_sz); + +/* Protocol */ +extern int semanage_node_get_proto(const semanage_node_t * node); + +extern void semanage_node_set_proto(semanage_node_t * node, int proto); + +extern const char *semanage_node_get_proto_str(int proto); + +/* Context */ +extern semanage_context_t *semanage_node_get_con(const semanage_node_t * node); + +extern int semanage_node_set_con(semanage_handle_t * handle, + semanage_node_t * node, + semanage_context_t * con); + +/* Create/Clone/Destroy */ +extern int semanage_node_create(semanage_handle_t * handle, + semanage_node_t ** node_ptr); + +extern int semanage_node_clone(semanage_handle_t * handle, + const semanage_node_t * node, + semanage_node_t ** node_ptr); + +extern void semanage_node_free(semanage_node_t * node); + +#endif
diff --git a/selinux/libsemanage/include/semanage/nodes_local.h b/selinux/libsemanage/include/semanage/nodes_local.h new file mode 100644 index 0000000..07ffd97 --- /dev/null +++ b/selinux/libsemanage/include/semanage/nodes_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_NODES_LOCAL_H_ +#define _SEMANAGE_NODES_LOCAL_H_ + +#include <semanage/node_record.h> +#include <semanage/handle.h> + +extern int semanage_node_modify_local(semanage_handle_t * handle, + const semanage_node_key_t * key, + const semanage_node_t * data); + +extern int semanage_node_del_local(semanage_handle_t * handle, + const semanage_node_key_t * key); + +extern int semanage_node_query_local(semanage_handle_t * handle, + const semanage_node_key_t * key, + semanage_node_t ** response); + +extern int semanage_node_exists_local(semanage_handle_t * handle, + const semanage_node_key_t * key, + int *response); + +extern int semanage_node_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_node_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_node_t * + record, void *varg), + void *handler_arg); + +extern int semanage_node_list_local(semanage_handle_t * handle, + semanage_node_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/nodes_policy.h b/selinux/libsemanage/include/semanage/nodes_policy.h new file mode 100644 index 0000000..9150dfc --- /dev/null +++ b/selinux/libsemanage/include/semanage/nodes_policy.h
@@ -0,0 +1,27 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_NODES_POLICY_H_ +#define _SEMANAGE_NODES_POLICY_H_ + +#include <semanage/handle.h> +#include <semanage/node_record.h> + +extern int semanage_node_query(semanage_handle_t * handle, + const semanage_node_key_t * key, + semanage_node_t ** response); + +extern int semanage_node_exists(semanage_handle_t * handle, + const semanage_node_key_t * key, int *response); + +extern int semanage_node_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_node_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_node_t * record, + void *varg), + void *handler_arg); + +extern int semanage_node_list(semanage_handle_t * handle, + semanage_node_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/port_record.h b/selinux/libsemanage/include/semanage/port_record.h new file mode 100644 index 0000000..20ae4bd --- /dev/null +++ b/selinux/libsemanage/include/semanage/port_record.h
@@ -0,0 +1,70 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_PORT_RECORD_H_ +#define _SEMANAGE_PORT_RECORD_H_ + +#include <semanage/context_record.h> +#include <semanage/handle.h> + +#ifndef _SEMANAGE_PORT_DEFINED_ +struct semanage_port; +struct semanage_port_key; +typedef struct semanage_port semanage_port_t; +typedef struct semanage_port_key semanage_port_key_t; +#define _SEMANAGE_PORT_DEFINED_ +#endif + +#define SEMANAGE_PROTO_UDP 0 +#define SEMANAGE_PROTO_TCP 1 + +/* Key */ +extern int semanage_port_compare(const semanage_port_t * port, + const semanage_port_key_t * key); + +extern int semanage_port_compare2(const semanage_port_t * port, + const semanage_port_t * port2); + +extern int semanage_port_key_create(semanage_handle_t * handle, + int low, int high, int proto, + semanage_port_key_t ** key_ptr); + +extern int semanage_port_key_extract(semanage_handle_t * handle, + const semanage_port_t * port, + semanage_port_key_t ** key_ptr); + +extern void semanage_port_key_free(semanage_port_key_t * key); + +/* Protocol */ +extern int semanage_port_get_proto(const semanage_port_t * port); + +extern void semanage_port_set_proto(semanage_port_t * port, int proto); + +extern const char *semanage_port_get_proto_str(int proto); + +/* Port */ +extern int semanage_port_get_low(const semanage_port_t * port); + +extern int semanage_port_get_high(const semanage_port_t * port); + +extern void semanage_port_set_port(semanage_port_t * port, int port_num); + +extern void semanage_port_set_range(semanage_port_t * port, int low, int high); + +/* Context */ +extern semanage_context_t *semanage_port_get_con(const semanage_port_t * port); + +extern int semanage_port_set_con(semanage_handle_t * handle, + semanage_port_t * port, + semanage_context_t * con); + +/* Create/Clone/Destroy */ +extern int semanage_port_create(semanage_handle_t * handle, + semanage_port_t ** port_ptr); + +extern int semanage_port_clone(semanage_handle_t * handle, + const semanage_port_t * port, + semanage_port_t ** port_ptr); + +extern void semanage_port_free(semanage_port_t * port); + +#endif
diff --git a/selinux/libsemanage/include/semanage/ports_local.h b/selinux/libsemanage/include/semanage/ports_local.h new file mode 100644 index 0000000..47cba44 --- /dev/null +++ b/selinux/libsemanage/include/semanage/ports_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_PORTS_LOCAL_H_ +#define _SEMANAGE_PORTS_LOCAL_H_ + +#include <semanage/port_record.h> +#include <semanage/handle.h> + +extern int semanage_port_modify_local(semanage_handle_t * handle, + const semanage_port_key_t * key, + const semanage_port_t * data); + +extern int semanage_port_del_local(semanage_handle_t * handle, + const semanage_port_key_t * key); + +extern int semanage_port_query_local(semanage_handle_t * handle, + const semanage_port_key_t * key, + semanage_port_t ** response); + +extern int semanage_port_exists_local(semanage_handle_t * handle, + const semanage_port_key_t * key, + int *response); + +extern int semanage_port_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_port_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_port_t * + record, void *varg), + void *handler_arg); + +extern int semanage_port_list_local(semanage_handle_t * handle, + semanage_port_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/ports_policy.h b/selinux/libsemanage/include/semanage/ports_policy.h new file mode 100644 index 0000000..364bce8 --- /dev/null +++ b/selinux/libsemanage/include/semanage/ports_policy.h
@@ -0,0 +1,27 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_PORTS_POLICY_H_ +#define _SEMANAGE_PORTS_POLICY_H_ + +#include <semanage/handle.h> +#include <semanage/port_record.h> + +extern int semanage_port_query(semanage_handle_t * handle, + const semanage_port_key_t * key, + semanage_port_t ** response); + +extern int semanage_port_exists(semanage_handle_t * handle, + const semanage_port_key_t * key, int *response); + +extern int semanage_port_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_port_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_port_t * record, + void *varg), + void *handler_arg); + +extern int semanage_port_list(semanage_handle_t * handle, + semanage_port_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/semanage.h b/selinux/libsemanage/include/semanage/semanage.h new file mode 100644 index 0000000..f417ce4 --- /dev/null +++ b/selinux/libsemanage/include/semanage/semanage.h
@@ -0,0 +1,55 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_SEMANAGE_H_ +#define _SEMANAGE_SEMANAGE_H_ + +#include <semanage/handle.h> +#include <semanage/modules.h> +#include <semanage/debug.h> + +/* Records */ +#include <semanage/boolean_record.h> +#include <semanage/user_record.h> +#include <semanage/seuser_record.h> +#include <semanage/context_record.h> +#include <semanage/iface_record.h> +#include <semanage/port_record.h> +#include <semanage/node_record.h> + +/* Dbase */ +#include <semanage/booleans_local.h> +#include <semanage/booleans_policy.h> +#include <semanage/booleans_active.h> +#include <semanage/users_local.h> +#include <semanage/users_policy.h> +#include <semanage/fcontexts_local.h> +#include <semanage/fcontexts_policy.h> +#include <semanage/seusers_local.h> +#include <semanage/seusers_policy.h> +#include <semanage/ports_local.h> +#include <semanage/ports_policy.h> +#include <semanage/interfaces_local.h> +#include <semanage/interfaces_policy.h> +#include <semanage/nodes_local.h> +#include <semanage/nodes_policy.h> + +#endif
diff --git a/selinux/libsemanage/include/semanage/seuser_record.h b/selinux/libsemanage/include/semanage/seuser_record.h new file mode 100644 index 0000000..bf0dc8e --- /dev/null +++ b/selinux/libsemanage/include/semanage/seuser_record.h
@@ -0,0 +1,61 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_SEUSER_RECORD_H_ +#define _SEMANAGE_SEUSER_RECORD_H_ + +#include <semanage/handle.h> + +struct semanage_seuser; +struct semanage_seuser_key; +typedef struct semanage_seuser semanage_seuser_t; +typedef struct semanage_seuser_key semanage_seuser_key_t; + +/* Key */ +extern int semanage_seuser_key_create(semanage_handle_t * handle, + const char *name, + semanage_seuser_key_t ** key); + +extern int semanage_seuser_key_extract(semanage_handle_t * handle, + const semanage_seuser_t * seuser, + semanage_seuser_key_t ** key); + +extern void semanage_seuser_key_free(semanage_seuser_key_t * key); + +extern int semanage_seuser_compare(const semanage_seuser_t * seuser, + const semanage_seuser_key_t * key); + +extern int semanage_seuser_compare2(const semanage_seuser_t * seuser, + const semanage_seuser_t * seuser2); + +/* Name */ +extern const char *semanage_seuser_get_name(const semanage_seuser_t * seuser); + +extern int semanage_seuser_set_name(semanage_handle_t * handle, + semanage_seuser_t * seuser, + const char *name); + +/* Selinux Name */ +extern const char *semanage_seuser_get_sename(const semanage_seuser_t * seuser); + +extern int semanage_seuser_set_sename(semanage_handle_t * handle, + semanage_seuser_t * seuser, + const char *sename); + +/* MLS */ +extern const char *semanage_seuser_get_mlsrange(const semanage_seuser_t * + seuser); + +extern int semanage_seuser_set_mlsrange(semanage_handle_t * handle, + semanage_seuser_t * seuser, + const char *mls_range); + +/* Create/Clone/Destroy */ +extern int semanage_seuser_create(semanage_handle_t * handle, + semanage_seuser_t ** seuser_ptr); + +extern int semanage_seuser_clone(semanage_handle_t * handle, + const semanage_seuser_t * seuser, + semanage_seuser_t ** seuser_ptr); + +extern void semanage_seuser_free(semanage_seuser_t * seuser); +#endif
diff --git a/selinux/libsemanage/include/semanage/seusers_local.h b/selinux/libsemanage/include/semanage/seusers_local.h new file mode 100644 index 0000000..4333a7b --- /dev/null +++ b/selinux/libsemanage/include/semanage/seusers_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_SEUSERS_LOCAL_H_ +#define _SEMANAGE_SEUSERS_LOCAL_H_ + +#include <semanage/seuser_record.h> +#include <semanage/handle.h> + +extern int semanage_seuser_modify_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + const semanage_seuser_t * data); + +extern int semanage_seuser_del_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key); + +extern int semanage_seuser_query_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + semanage_seuser_t ** response); + +extern int semanage_seuser_exists_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + int *response); + +extern int semanage_seuser_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_seuser_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_seuser_t + * record, void *varg), + void *handler_arg); + +extern int semanage_seuser_list_local(semanage_handle_t * handle, + semanage_seuser_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/seusers_policy.h b/selinux/libsemanage/include/semanage/seusers_policy.h new file mode 100644 index 0000000..8d39d45 --- /dev/null +++ b/selinux/libsemanage/include/semanage/seusers_policy.h
@@ -0,0 +1,29 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_SEUSERS_POLICY_H_ +#define _SEMANAGE_SEUSERS_POLICY_H_ + +#include <semanage/seuser_record.h> +#include <semanage/handle.h> + +extern int semanage_seuser_query(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + semanage_seuser_t ** response); + +extern int semanage_seuser_exists(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + int *response); + +extern int semanage_seuser_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_seuser_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_seuser_t * + record, void *varg), + void *handler_arg); + +extern int semanage_seuser_list(semanage_handle_t * handle, + semanage_seuser_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/user_record.h b/selinux/libsemanage/include/semanage/user_record.h new file mode 100644 index 0000000..d4a4866 --- /dev/null +++ b/selinux/libsemanage/include/semanage/user_record.h
@@ -0,0 +1,90 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_USER_RECORD_H_ +#define _SEMANAGE_USER_RECORD_H_ + +#include <stddef.h> +#include <semanage/handle.h> + +struct semanage_user; +typedef struct semanage_user semanage_user_t; + +#ifndef _SEMANAGE_USER_KEY_DEFINED_ +struct semanage_user_key; +typedef struct semanage_user_key semanage_user_key_t; +#define _SEMANAGE_USER_KEY_DEFINED_ +#endif + +/* Key */ +extern int semanage_user_key_create(semanage_handle_t * handle, + const char *name, + semanage_user_key_t ** key); + +extern int semanage_user_key_extract(semanage_handle_t * handle, + const semanage_user_t * user, + semanage_user_key_t ** key); + +extern void semanage_user_key_free(semanage_user_key_t * key); + +extern int semanage_user_compare(const semanage_user_t * user, + const semanage_user_key_t * key); + +extern int semanage_user_compare2(const semanage_user_t * user, + const semanage_user_t * user2); + +/* Name */ +extern const char *semanage_user_get_name(const semanage_user_t * user); + +extern int semanage_user_set_name(semanage_handle_t * handle, + semanage_user_t * user, const char *name); + +/* Labeling prefix */ +extern const char *semanage_user_get_prefix(const semanage_user_t * user); + +extern int semanage_user_set_prefix(semanage_handle_t * handle, + semanage_user_t * user, const char *name); + +/* MLS */ +extern const char *semanage_user_get_mlslevel(const semanage_user_t * user); + +extern int semanage_user_set_mlslevel(semanage_handle_t * handle, + semanage_user_t * user, + const char *mls_level); + +extern const char *semanage_user_get_mlsrange(const semanage_user_t * user); + +extern int semanage_user_set_mlsrange(semanage_handle_t * handle, + semanage_user_t * user, + const char *mls_range); + +/* Role management */ +extern int semanage_user_get_num_roles(const semanage_user_t * user); + +extern int semanage_user_add_role(semanage_handle_t * handle, + semanage_user_t * user, const char *role); + +extern void semanage_user_del_role(semanage_user_t * user, const char *role); + +extern int semanage_user_has_role(const semanage_user_t * user, + const char *role); + +extern int semanage_user_get_roles(semanage_handle_t * handle, + const semanage_user_t * user, + const char ***roles_arr, + unsigned int *num_roles); + +extern int semanage_user_set_roles(semanage_handle_t * handle, + semanage_user_t * user, + const char **roles_arr, + unsigned int num_roles); + +/* Create/Clone/Destroy */ +extern int semanage_user_create(semanage_handle_t * handle, + semanage_user_t ** user_ptr); + +extern int semanage_user_clone(semanage_handle_t * handle, + const semanage_user_t * user, + semanage_user_t ** user_ptr); + +extern void semanage_user_free(semanage_user_t * user); +#endif
diff --git a/selinux/libsemanage/include/semanage/users_local.h b/selinux/libsemanage/include/semanage/users_local.h new file mode 100644 index 0000000..952474c --- /dev/null +++ b/selinux/libsemanage/include/semanage/users_local.h
@@ -0,0 +1,36 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_USERS_LOCAL_H_ +#define _SEMANAGE_USERS_LOCAL_H_ + +#include <semanage/user_record.h> +#include <semanage/handle.h> + +extern int semanage_user_modify_local(semanage_handle_t * handle, + const semanage_user_key_t * key, + const semanage_user_t * data); + +extern int semanage_user_del_local(semanage_handle_t * handle, + const semanage_user_key_t * key); + +extern int semanage_user_query_local(semanage_handle_t * handle, + const semanage_user_key_t * key, + semanage_user_t ** response); + +extern int semanage_user_exists_local(semanage_handle_t * handle, + const semanage_user_key_t * key, + int *response); + +extern int semanage_user_count_local(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_user_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_user_t * + record, void *varg), + void *handler_arg); + +extern int semanage_user_list_local(semanage_handle_t * handle, + semanage_user_t *** records, + unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/include/semanage/users_policy.h b/selinux/libsemanage/include/semanage/users_policy.h new file mode 100644 index 0000000..b1677ec --- /dev/null +++ b/selinux/libsemanage/include/semanage/users_policy.h
@@ -0,0 +1,27 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_USERS_POLICY_H_ +#define _SEMANAGE_USERS_POLICY_H_ + +#include <semanage/handle.h> +#include <semanage/user_record.h> + +extern int semanage_user_query(semanage_handle_t * handle, + const semanage_user_key_t * key, + semanage_user_t ** response); + +extern int semanage_user_exists(semanage_handle_t * handle, + const semanage_user_key_t * key, int *response); + +extern int semanage_user_count(semanage_handle_t * handle, + unsigned int *response); + +extern int semanage_user_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_user_t * record, + void *varg), + void *handler_arg); + +extern int semanage_user_list(semanage_handle_t * handle, + semanage_user_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/man/Makefile b/selinux/libsemanage/man/Makefile new file mode 100644 index 0000000..852043d --- /dev/null +++ b/selinux/libsemanage/man/Makefile
@@ -0,0 +1,12 @@ +# Installation directories. +MAN3DIR ?= $(DESTDIR)/usr/share/man/man3 +MAN5DIR ?= $(DESTDIR)/usr/share/man/man5 + +all: + +install: all + mkdir -p $(MAN3DIR) + mkdir -p $(MAN5DIR) + install -m 644 man3/*.3 $(MAN3DIR) + install -m 644 man5/*.5 $(MAN5DIR) +
diff --git a/selinux/libsemanage/man/man3/semanage_bool.3 b/selinux/libsemanage/man/man3/semanage_bool.3 new file mode 100644 index 0000000..67da632 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool.3
@@ -0,0 +1,177 @@ +.TH semanage_bool 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_bool \- SELinux Policy Booleans Management API + +.SH "SYNOPSIS" +.B #include <semanage/boolean_record.h> +.br +.B #include <semanage/booleans_active.h> +.br +.B #include <semanage/booleans_policy.h> +.br +.B #include <semanage/booleans_local.h> + +.PP +This object contains properties associated with a SELinux policy boolean + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_bool_create "(3)" \- +.br +create a boolean + +.HP +.BR semanage_bool_free "(3)" \- +.br +release resources for this boolean + +.HP +.BR semanage_bool_key_create "(3)" \- +.br +create a key, which can be used to identify a boolean + +.HP +.BR semanage_bool_key_free "(3)" \- +.br +release resources for this boolean key + +.HP +.BR semanage_bool_key_extract "(3)" \- +.br +create a key matching this boolean + +.HP +.BR semanage_bool_clone "(3)" \- +.br +create an identical boolean (deep-copy clone) + +.HP +.BR semanage_bool_compare "(3)" \- +.br +compare this boolean to the provided key + +.HP +.BR semanage_bool_compare2 "(3)" \- +.br +compare this boolean to another + + +.SH "Properties API Overview" + +.HP +.BR semanage_bool_get_name "(3)" \- +.br +return the name of this boolean + +.HP +.BR semanage_bool_set_name "(3)" \- +.br +set the name of this boolean + +.HP +.BR semanage_bool_get_value "(3)" \- +.br +return the value of this boolean + +.HP +.BR semanage_bool_set_value "(3)" \- +.br +set the value of this boolean + + +.SH "Record Store API Overview" + +.HP +.BR semanage_bool_modify_local "(3)" \- +.br +add or update a boolean in the local store + +.HP +.BR semanage_bool_set_active "(3)" \- +.br +update a boolean in the currently active policy + +.HP +.BR semanage_bool_del_local "(3)" \- +.br +delete a boolean from the local store + +.HP +.BR semanage_bool_exists "(3)" \- +.br +check if a boolean is defined in the persistent policy + +.HP +.BR semanage_bool_exists_local "(3)" \- +.br +check if a boolean is defined in the local store + +.HP +.BR semanage_bool_exists_active "(3)" \- +.br +check if a boolean is defined in the currently active policy + +.HP +.BR semanage_bool_query "(3)" \- +.br +query a boolean in the persistent policy + +.HP +.BR semanage_bool_query_local "(3)" \- +.br +query a boolean in the local store + +.HP +.BR semanage_bool_query_active "(3)" \- +.br +query a boolean in the currently active policy + +.HP +.BR semanage_bool_count "(3)" \- +.br +count the number of booleans defined in the persistent policy + +.HP +.BR semanage_bool_count_local "(3)" \- +.br +count the number of booleans defined in the local store + +.HP +.BR semanage_bool_count_active "(3)" \- +.br +count the number of booleans defined in the currently active policy + +.HP +.BR semanage_bool_iterate "(3)" \- +.br +execute a callback for each boolean in the persistent policy + +.HP +.BR semanage_bool_iterate_local "(3)" \- +.br +execute a callback for each boolean in the local store + +.HP +.BR semanage_bool_iterate_active "(3)" \- +.br +execute a callback for each boolean in the currently active policy + +.HP +.BR semanage_bool_list "(3)" \- +.br +return an array containing all booleans in the persistent policy + +.HP +.BR semanage_bool_list_local "(3)" \- +.br +return an array containing all booleans in the local store + +.HP +.BR semanage_bool_list_active "(3)" \- +.br +return an array containing all booleans in the currently active policy
diff --git a/selinux/libsemanage/man/man3/semanage_bool_count.3 b/selinux/libsemanage/man/man3/semanage_bool_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_count_active.3 b/selinux/libsemanage/man/man3/semanage_bool_count_active.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_count_active.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_count_local.3 b/selinux/libsemanage/man/man3/semanage_bool_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_del_local.3 b/selinux/libsemanage/man/man3/semanage_bool_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_exists.3 b/selinux/libsemanage/man/man3/semanage_bool_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_exists_active.3 b/selinux/libsemanage/man/man3/semanage_bool_exists_active.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_exists_active.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_exists_local.3 b/selinux/libsemanage/man/man3/semanage_bool_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_iterate.3 b/selinux/libsemanage/man/man3/semanage_bool_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_iterate_active.3 b/selinux/libsemanage/man/man3/semanage_bool_iterate_active.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_iterate_active.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_bool_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_list.3 b/selinux/libsemanage/man/man3/semanage_bool_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_list_active.3 b/selinux/libsemanage/man/man3/semanage_bool_list_active.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_list_active.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_list_local.3 b/selinux/libsemanage/man/man3/semanage_bool_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_modify_local.3 b/selinux/libsemanage/man/man3/semanage_bool_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_query.3 b/selinux/libsemanage/man/man3/semanage_bool_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_query_active.3 b/selinux/libsemanage/man/man3/semanage_bool_query_active.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_query_active.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_query_local.3 b/selinux/libsemanage/man/man3/semanage_bool_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_bool_set_active.3 b/selinux/libsemanage/man/man3/semanage_bool_set_active.3 new file mode 100644 index 0000000..d868fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_bool_set_active.3
@@ -0,0 +1,47 @@ +.TH semanage_bool_set_local 3 "4 January 2006" "ivg2@cornell.edu" "Libsemanage API documentation" +.SH "NAME" +semanage_bool_set_active \- update an existing SELinux boolean in the currently active policy + +.SH "SYNOPSIS" +.B #include <semanage/booleans_active.h> +.br +.sp +.B extern int semanage_bool_set_active ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " const semanage_bool_key_t *" key "," +.br +.BI " const semanage_bool_t *" data ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The set function will fail if no matching key is found in the local store. Otherwise, the provided object will replace the current one. When +.BR semanage_commit "(3)" +is invoked, changes will be written permanently into the local store, and will be loaded into policy. Validity of the object being added is checked at commit time. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I key +identifies the +.I data +object, which will be written into the store. The key are data are properties of the caller, and are not stored or modified internally. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +), and must be executed in a transaction (see +.BR semanage_begin_transaction "(3)" +). + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise 0 is returned. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_begin_transaction "(3), " semanage_connect "(3), " semanage_commit "(3). "
diff --git a/selinux/libsemanage/man/man3/semanage_count.3 b/selinux/libsemanage/man/man3/semanage_count.3 new file mode 100644 index 0000000..b865a21 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_count.3
@@ -0,0 +1,40 @@ +.TH semanage_count 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_count \- SELinux Management API + +.SH "SYNOPSIS" +The following count function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int COUNT_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " unsigned int* " response ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The count function will return the number of all objects in the selected location. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The number of objects will be stored at the location poined by +.I response. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +) + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise a non-negative integer is returned (a commit number). The same number will be returned by all other semanage object read calls until the next commit. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_del.3 b/selinux/libsemanage/man/man3/semanage_del.3 new file mode 100644 index 0000000..4dd0a77 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_del.3
@@ -0,0 +1,47 @@ +.TH semanage_del 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_del \- SELinux Management API + +.SH "SYNOPSIS" +The following delete function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int DELETE_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " const semanage_OBJECT_key_t *" key ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The delete function will remove the object corresponding to the provided key from the local store. If no match is found, no action is taken. Changes will become permanent when +.BR semanage_commit "(3)" +is invoked. Additional checks may be performed at that time to ensure the system is left in a valid state. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I key +identifies the +.I data +object, which will be deleted from the local store. The key is a property of the caller, and will not be stored or modified internally. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +), and must be executed in a transaction (see +.BR semanage_begin_transaction "(3)" +). + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise 0 is returned. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_begin_transaction "(3), " semanage_connect "(3), " semanage_commit "(3). "
diff --git a/selinux/libsemanage/man/man3/semanage_exists.3 b/selinux/libsemanage/man/man3/semanage_exists.3 new file mode 100644 index 0000000..6d68c76 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_exists.3
@@ -0,0 +1,45 @@ +.TH semanage_exists 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_exists \- SELinux Management API + +.SH "SYNOPSIS" +The following exists function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int EXISTS_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " const semanage_OBJECT_key_t *" key "," +.br +.BI " semanage_OBJECT_t **" response ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The exists function will return 0 if a matching key is not found, and 1 otherwise. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I key +identifies the object being checked. The result of the test will be stored in the address pointed by +.I response +The key is a property of the caller, and will not be stored or modified internally. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +) + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise a non-negative integer is returned (a commit number). The same number will be returned by all other read calls to the semanage database until the next commit. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext.3 b/selinux/libsemanage/man/man3/semanage_fcontext.3 new file mode 100644 index 0000000..1f0bf32 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext.3
@@ -0,0 +1,160 @@ +.TH semanage_fcontext 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_fcontext \- SELinux File Context Management API + +.SH "SYNOPSIS" +.B #include <semanage/fcontext_record.h> +.br +.B #include <semanage/fcontexts_policy.h> +.br +.B #include <semanage/fcontexts_local.h> + +.PP +This object contains properties associated with a SELinux file context specification + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_fcontext_create "(3)" \- +.br +create a file context spec + +.HP +.BR semanage_fcontext_free "(3)" \- +.br +release resources for this file context spec + +.HP +.BR semanage_fcontext_key_create "(3)" \- +.br +create a key, which can be used to identify a file context spec + +.HP +.BR semanage_fcontext_key_free "(3)" \- +.br +release resources for this file context spec key + +.HP +.BR semanage_fcontext_key_extract "(3)" \- +.br +create a key matching this file context spec + +.HP +.BR semanage_fcontext_clone "(3)" \- +.br +create an identical file context spec (deep-copy clone) + +.HP +.BR semanage_fcontext_compare "(3)" \- +.br +compare this file context spec to the provided key + +.HP +.BR semanage_fcontext_compare2 "(3)" \- +.br +compare this file context spec to another + + +.SH "Properties API Overview" + +.HP +.BR semanage_fcontext_get_expr "(3)" \- +.br +return the regular expression for this file context spec + +.HP +.BR semanage_fcontext_set_expr "(3)" \- +.br +set the regular expression for this file context spec + +.HP +.BR semanage_fcontext_get_type "(3)" \- +.br +return the file type for this file context spec + +.HP +.BR semanage_fcontext_get_type_str "(3)" \- +.br +return a string representation for this file context spec type + +.HP +.BR semanage_fcontext_set_type "(3)" \- +.br +set the file type for this file context spec + +.HP +.BR semanage_fcontext_get_con "(3)" \- +.br +return the SELinux context for this file context spec + +.HP +.BR semanage_fcontext_set_expr "(3)" \- +.br +set the SELinux context for this file context spec + + +.SH "Record Store API Overview" + +.HP +.BR semanage_fcontext_modify_local "(3)" \- +.br +add or update a file context spec in the local store + +.HP +.BR semanage_fcontext_del_local "(3)" \- +.br +delete a file context spec from the local store + +.HP +.BR semanage_fcontext_exists "(3)" \- +.br +check if a file context spec is defined in the persistent policy + +.HP +.BR semanage_fcontext_exists_local "(3)" \- +.br +check if a file context spec is defined in the local store + +.HP +.BR semanage_fcontext_query "(3)" \- +.br +query a file context spec in the persistent policy + +.HP +.BR semanage_fcontext_query_local "(3)" \- +.br +query a file context spec in the local store + +.HP +.BR semanage_fcontext_count "(3)" \- +.br +count the number of file context specs defined in the persistent policy + +.HP +.BR semanage_fcontext_count_local "(3)" \- +.br +count the number of file context specs defined in the local store + +.HP +.BR semanage_fcontext_iterate "(3)" \- +.br +execute a callback for each file context spec in the persistent policy + +.HP +.BR semanage_fcontext_iterate_local "(3)" \- +.br +execute a callback for each file context spec in the local store + +.HP +.BR semanage_fcontext_list "(3)" \- +.br +return an array containing all file context specs in the persistent policy + +.HP +.BR semanage_fcontext_list_local "(3)" \- +.br +return an array containing all file context specs in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_count.3 b/selinux/libsemanage/man/man3/semanage_fcontext_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_count_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_del_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_exists.3 b/selinux/libsemanage/man/man3/semanage_fcontext_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_exists_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_iterate.3 b/selinux/libsemanage/man/man3/semanage_fcontext_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_list.3 b/selinux/libsemanage/man/man3/semanage_fcontext_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_list_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_modify_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_query.3 b/selinux/libsemanage/man/man3/semanage_fcontext_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_fcontext_query_local.3 b/selinux/libsemanage/man/man3/semanage_fcontext_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_fcontext_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface.3 b/selinux/libsemanage/man/man3/semanage_iface.3 new file mode 100644 index 0000000..90af8b4 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface.3
@@ -0,0 +1,153 @@ +.TH semanage_iface 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_iface \- SELinux Network Interfaces Management API + +.SH "SYNOPSIS" +.B #include <semanage/iface_record.h> +.br +.B #include <semanage/interfaces_policy.h> +.br +.B #include <semanage/interfaces_local.h> + +.PP +This object contains properties associated with a network interface. + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_iface_create "(3)" \- +.br +create an interface + +.HP +.BR semanage_iface_free "(3)" \- +.br +release resources for this interface + +.HP +.BR semanage_iface_key_create "(3)" \- +.br +create a key, which can be used to identify an interface + +.HP +.BR semanage_iface_key_free "(3)" \- +.br +release resources for this interface key + +.HP +.BR semanage_iface_key_extract "(3)" \- +.br +create a key matching this interface + +.HP +.BR semanage_iface_clone "(3)" \- +.br +create an identical interface (deep-copy clone) + +.HP +.BR semanage_iface_compare "(3)" \- +.br +compare this interface to the provided key + +.HP +.BR semanage_iface_compare2 "(3)" \- +.br +compare this interface to another + +.SH "Properties API Overview" + +.HP +.BR semanage_iface_get_name "(3)" \- +.br +return the name of this interface + +.HP +.BR semanage_iface_set_name "(3)" \- +.br +set the name of this interface + +.HP +.BR semanage_iface_get_ifcon "(3)" \- +.br +return the SELinux context associated with this interface + +.HP +.BR semanage_iface_set_ifcon "(3)" \- +.br +set the SELinux context associated with this interface + +.HP +.BR semanage_iface_get_msgcon "(3)" \- +.br +return the SELinux context associated with packets sent over this interface + +.HP +.BR semanage_iface_set_msgcon "(3)" \- +.br +set the SELinux context associated with packets sent over this interface + +.SH "Record Store API Overview" + +.HP +.BR semanage_iface_modify_local "(3)" \- +.br +add or update an interface in the local store + +.HP +.BR semanage_iface_del_local "(3)" \- +.br +delete an interface from the local store + +.HP +.BR semanage_iface_exists "(3)" \- +.br +check if an interface is defined in the persistent policy + +.HP +.BR semanage_iface_exists_local "(3)" \- +.br +check if an interface is defined in the local store + +.HP +.BR semanage_iface_query "(3)" \- +.br +query an interface in the persistent policy + +.HP +.BR semanage_iface_query_local "(3)" \- +.br +query an interface in the local store + +.HP +.BR semanage_iface_count "(3)" \- +.br +count the number of interfaces defined in the persistent policy + +.HP +.BR semanage_iface_count_local "(3)" \- +.br +count the number of interfaces defined in the local store + +.HP +.BR semanage_iface_iterate "(3)" \- +.br +execute a callback for each interface in the persistent policy + +.HP +.BR semanage_iface_iterate_local "(3)" \- +.br +execute a callback for each interface in the local store + +.HP +.BR semanage_iface_list "(3)" \- +.br +return an array containing all interfaces in the persistent policy + +.HP +.BR semanage_iface_list_local "(3)" \- +.br +return an array containing all interfaces in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_iface_count.3 b/selinux/libsemanage/man/man3/semanage_iface_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_count_local.3 b/selinux/libsemanage/man/man3/semanage_iface_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_del_local.3 b/selinux/libsemanage/man/man3/semanage_iface_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_exists.3 b/selinux/libsemanage/man/man3/semanage_iface_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_exists_local.3 b/selinux/libsemanage/man/man3/semanage_iface_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_iterate.3 b/selinux/libsemanage/man/man3/semanage_iface_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_iface_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_list.3 b/selinux/libsemanage/man/man3/semanage_iface_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_list_local.3 b/selinux/libsemanage/man/man3/semanage_iface_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_modify_local.3 b/selinux/libsemanage/man/man3/semanage_iface_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_query.3 b/selinux/libsemanage/man/man3/semanage_iface_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_iface_query_local.3 b/selinux/libsemanage/man/man3/semanage_iface_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iface_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_iterate.3 b/selinux/libsemanage/man/man3/semanage_iterate.3 new file mode 100644 index 0000000..1528164 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_iterate.3
@@ -0,0 +1,57 @@ +.TH semanage_iterate 3 "15 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_iterate \- SELinux Management API + +.SH "SYNOPSIS" +The following iterate function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int ITERATE_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " int (*handler) ( +.br +.BI " const semanage_OBJECT_t *" object "," +.br +.BI " void *" varg ")," +.br +.BI " void *" handler_arg ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The iterate function will execute the specified handler over all objects in the selected location. An arbitrary argument can be passed into the handler function along with each object. + +The object passed in is property of the libsemanage library, and may not be modified or preserved - use +.B semanage_OBJECT_clone +if that is necessary. + +The handler code may not invoke any semanage write requests for the same object type (i.e. modifying the underlying store is not allowed). The iterate function is reentrant only while inside a transaction (see +.B semanage_begin_transaction +). It is not safe to execute other semanage read or write requests within iterate if not inside a transaction. The handler may return \-1 to signal error exit, 0 to signal continue, and 1 to signal successful exit early (the iterate function will stop accordingly). + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I handler +is the function to execute, with +.I handler_arg +as its second parameter, and each object as its first parameter. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +) + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise a non-negative integer is returned (a commit number). The same number will be returned by all other semanage object read calls until the next commit. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_list.3 b/selinux/libsemanage/man/man3/semanage_list.3 new file mode 100644 index 0000000..acc161f --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_list.3
@@ -0,0 +1,46 @@ +.TH semanage_list 3 "16 March 2006" "ivg2@cornell.edu" "SELinux managent API documentation" + +.SH "NAME" +semanage_list \- SELinux Lists Management API + +.SH "SYNOPSIS" +The following list function is supported for any SELinux managent record. +.br +Replace the function and object name as necessary. + +.B extern int LIST_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " semanage_OBJECT_t ***" objects "," +.br +.BI " unsigned int* " count ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The list function will return an array of all the objects in the selected location. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The function will allocate and populate the the array of objects, and store it at the location pointed by +.I objects. +It will write the number of objects at the location pointed by +.I count. +The array, and all its objects become property of the caller. Each object must be freed with +.B semanage_OBJECT_free. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +) + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise a non-negative integer is returned (a commit number). The same number will be returned by all other semanage object read calls until the next commit. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_modify.3 b/selinux/libsemanage/man/man3/semanage_modify.3 new file mode 100644 index 0000000..ee23900 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_modify.3
@@ -0,0 +1,49 @@ +.TH semanage_modify 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_modify \- SELinux Management API + +.SH "SYNOPSIS" +The following modify function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int MODIFY_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " const semanage_OBJECT_key_t *" key "," +.br +.BI " const semanage_OBJECT_t *" data ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +If a matching key is found in the local store, the provided object will replace the current one. Otherwise, it will be added to the store. When +.BR semanage_commit "(3)" +is invoked, changes will be permanently written into the local store, and then loaded into policy. Validity of the object being added is checked at commit time. Adding new objects with respect to policy is allowed, except in the case of booleans. Attempt to add new booleans with respect to policy will fail at commit time. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I key +identifies the +.I data +object, which will be written into the store. The key are data are properties of the caller, and are not stored or modified internally. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +), and must be executed in a transaction (see +.BR semanage_begin_transaction "(3)" +). + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise 0 is returned. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_begin_transaction "(3), " semanage_connect "(3), " semanage_commit "(3). "
diff --git a/selinux/libsemanage/man/man3/semanage_node.3 b/selinux/libsemanage/man/man3/semanage_node.3 new file mode 100644 index 0000000..2df7a91 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node.3
@@ -0,0 +1,188 @@ +.TH semanage_node 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_node \- SELinux Network Nodes Management API + +.SH "SYNOPSIS" +.B #include <semanage/node_record.h> +.br +.B #include <semanage/nodes_policy.h> +.br +.B #include <semanage/nodes_local.h> + +.PP +This object contains properties associated with a network node. + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_node_create "(3)" \- +.br +create a node + +.HP +.BR semanage_node_free "(3)" \- +.br +release resources for this node + +.HP +.BR semanage_node_key_create "(3)" \- +.br +create a key, which can be used to identify a node + +.HP +.BR semanage_node_key_free "(3)" \- +.br +release resources for this node key + +.HP +.BR semanage_node_key_extract "(3)" \- +.br +create a key matching this node + +.HP +.BR semanage_node_clone "(3)" \- +.br +create an identical node (deep-copy clone) + +.HP +.BR semanage_node_compare "(3)" \- +.br +compare this node to the provided key + +.HP +.BR semanage_node_compare2 "(3)" \- +.br +compare this node to another + +.SH "Properties API Overview" + +.HP +.BR semanage_node_get_addr "(3)" \- +.br +return the IP address of this node in string representation + +.HP +.BR semanage_node_set_addr "(3)" \- +.br +set the IP address of this node from the provided string representation and protocol + +.HP +.BR semanage_node_get_addr_bytes "(3)" \- +.br +return the IP address of this node as a byte array in network byte order + +.HP +.BR semanage_node_set_addr_bytes "(3)" \- +.br +set the IP address of this node from the provided byte array in network byte order + +.HP +.BR semanage_node_get_mask "(3)" \- +.br +return the IP mask of this node in string representation + +.HP +.BR semanage_node_set_mask "(3)" \- +.br +set the IP mask of this node from the provided string representation and protocol version + +.HP +.BR semanage_node_get_mask_bytes "(3)" \- +.br +return the IP mask of this node as a byte array in network byte order + +.HP +.BR semanage_node_set_mask_bytes "(3)" \- +.br +set the IP mask of this node from the provided byte array in network byte order + +.HP +.BR semanage_node_get_proto "(3)" \- +.br +return the IP protocol version for this node + +.HP +.BR semanage_node_get_proto_str "(3)" \- +.br +return a string representation of the given node protocol + +.HP +.BR semanage_node_set_proto "(3)" \- +.br +set the IP protocol version for this node + +.HP +.BR semanage_node_get_con "(3)" \- +.br +return the SELinux context associated with this node + +.HP +.BR semanage_node_set_con "(3)" \- +.br +set the SELinux context associated with this node + +.SH "Record Store API Overview" + +.HP +.BR semanage_node_modify_local "(3)" \- +.br +add or update an interface in the local store + +.HP +.BR semanage_node_del_local "(3)" \- +.br +delete an interface from the local store + +.HP +.BR semanage_node_exists "(3)" \- +.br +check if an interface is defined in the persistent policy + +.HP +.BR semanage_node_exists_local "(3)" \- +.br +check if an interface is defined in the local store + +.HP +.BR semanage_node_query "(3)" \- +.br +query an interface in the persistent policy + +.HP +.BR semanage_node_query_local "(3)" \- +.br +query an interface in the local store + +.HP +.BR semanage_node_count "(3)" \- +.br +count the number of nodes defined in the persistent policy + +.HP +.BR semanage_node_count_local "(3)" \- +.br +count the number of nodes defined in the local store + +.HP +.BR semanage_node_iterate "(3)" \- +.br +execute a callback for each interface in the persistent policy + +.HP +.BR semanage_node_iterate_local "(3)" \- +.br +execute a callback for each interface in the local store + +.HP +.BR semanage_node_list "(3)" \- +.br +return an array containing all nodes in the persistent policy + +.HP +.BR semanage_node_list_local "(3)" \- +.br +return an array containing all nodes in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_node_count.3 b/selinux/libsemanage/man/man3/semanage_node_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_count_local.3 b/selinux/libsemanage/man/man3/semanage_node_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_del_local.3 b/selinux/libsemanage/man/man3/semanage_node_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_exists.3 b/selinux/libsemanage/man/man3/semanage_node_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_exists_local.3 b/selinux/libsemanage/man/man3/semanage_node_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_iterate.3 b/selinux/libsemanage/man/man3/semanage_node_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_node_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_list.3 b/selinux/libsemanage/man/man3/semanage_node_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_list_local.3 b/selinux/libsemanage/man/man3/semanage_node_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_modify_local.3 b/selinux/libsemanage/man/man3/semanage_node_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_query.3 b/selinux/libsemanage/man/man3/semanage_node_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_node_query_local.3 b/selinux/libsemanage/man/man3/semanage_node_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_node_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_port.3 b/selinux/libsemanage/man/man3/semanage_port.3 new file mode 100644 index 0000000..3a4e626 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port.3
@@ -0,0 +1,169 @@ +.TH semanage_port 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_port \- SELinux Network Ports Management API + +.SH "SYNOPSIS" +.B #include <semanage/port_record.h> +.br +.B #include <semanage/ports_policy.h> +.br +.B #include <semanage/ports_local.h> + +.PP +This object contains properties associated with a range of network ports. + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_port_create "(3)" \- +.br +create a port range + +.HP +.BR semanage_port_free "(3)" \- +.br +release resources for this port range + +.HP +.BR semanage_port_key_create "(3)" \- +.br +create a key, which can be used to identify a port range + +.HP +.BR semanage_port_key_free "(3)" \- +.br +release resources for this port range key + +.HP +.BR semanage_port_key_extract "(3)" \- +.br +create a key matching this port range + +.HP +.BR semanage_port_clone "(3)" \- +.br +create an identical port range (deep-copy clone) + +.HP +.BR semanage_port_compare "(3)" \- +.br +compare this port range to the provided key + +.HP +.BR semanage_port_compare2 "(3)" \- +.br +compare this port range to another + +.SH "Properties API Overview" + +.HP +.BR semanage_port_get_proto "(3)" \- +.br +return the protocol for this port range + +.HP +.BR semanage_port_get_proto_str "(3)" \- +.br +return a string representation of the given port protocol + +.HP +.BR semanage_port_set_proto "(3)" \- +.br +set the protocol for this port range + +.HP +.BR semanage_port_get_low "(3)" \- +.br +return the low port number for this port range + +.HP +.BR semanage_port_get_high "(3)" \- +.br +return the high port number for this port range + +.HP +.BR semanage_port_set_port "(3)" \- +.br +set the port number (same low and high) for this port range + +.HP +.BR semanage_port_set_range "(3)" \- +.br +set the low and high port number for this port range + +.HP +.BR semanage_port_get_con "(3)" \- +.br +return the SELinux context for this port range + +.HP +.BR semanage_port_set_con "(3)" \- +.br +set the SELinux context for this port range + + +.SH "Record Store API Overview" + +.HP +.BR semanage_port_modify_local "(3)" \- +.br +add or update a port range in the local store + +.HP +.BR semanage_port_del_local "(3)" \- +.br +delete a port range from the local store + +.HP +.BR semanage_port_exists "(3)" \- +.br +check if a port range is defined in the persistent policy + +.HP +.BR semanage_port_exists_local "(3)" \- +.br +check if a port range is defined in the local store + +.HP +.BR semanage_port_query "(3)" \- +.br +query a port range in the persistent policy + +.HP +.BR semanage_port_query_local "(3)" \- +.br +query a port range in the local store + +.HP +.BR semanage_port_count "(3)" \- +.br +count the number of port ranges defined in the persistent policy + +.HP +.BR semanage_port_count_local "(3)" \- +.br +count the number of port ranges defined in the local store + +.HP +.BR semanage_port_iterate "(3)" \- +.br +execute a callback for each port range in the persistent policy + +.HP +.BR semanage_port_iterate_local "(3)" \- +.br +execute a callback for each port range in the local store + +.HP +.BR semanage_port_list "(3)" \- +.br +return an array containing all port ranges in the persistent policy + +.HP +.BR semanage_port_list_local "(3)" \- +.br +return an array containing all port ranges in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_port_count.3 b/selinux/libsemanage/man/man3/semanage_port_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_count_local.3 b/selinux/libsemanage/man/man3/semanage_port_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_del_local.3 b/selinux/libsemanage/man/man3/semanage_port_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_exists.3 b/selinux/libsemanage/man/man3/semanage_port_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_exists_local.3 b/selinux/libsemanage/man/man3/semanage_port_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_iterate.3 b/selinux/libsemanage/man/man3/semanage_port_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_port_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_list.3 b/selinux/libsemanage/man/man3/semanage_port_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_list_local.3 b/selinux/libsemanage/man/man3/semanage_port_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_modify_local.3 b/selinux/libsemanage/man/man3/semanage_port_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_query.3 b/selinux/libsemanage/man/man3/semanage_port_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_port_query_local.3 b/selinux/libsemanage/man/man3/semanage_port_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_port_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_query.3 b/selinux/libsemanage/man/man3/semanage_query.3 new file mode 100644 index 0000000..e61c8b8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_query.3
@@ -0,0 +1,46 @@ +.TH semanage_query 3 "15 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_query \- SELinux Management API + +.SH "SYNOPSIS" +The following query function is supported for any semanage record. +.br +Replace the function and object name as necessary. + +.B extern int QUERY_FUNCTION ( +.br +.BI " semanage_handle_t *" handle "," +.br +.BI " const semanage_OBJECT_key_t *" key "," +.br +.BI " semanage_OBJECT_t **" response ");" + +.SH "DESCRIPTION" +.TP +.B Behavior: +The query function will fail if a matching key is not found. Otherwise, the corresponding object is returned. + +.TP +.B Parameters: +The +.I handle +is used to track persistent state across semanage calls, and for error reporting. The +.I key +identifies the object being queried, which will be stored in the address pointed by +.I response +The key is a property of the caller, and will not be stored or modified internally. The object returned becomes a property of the caller, and must be freed with +.B semanage_OBJECT_free. + +.TP +.B Requirements: +This function requires an semanage connection to be established (see +.BR semanage_connect "(3)" +) + +.SH "RETURN VALUE" +In case of failure, \-1 is returned, and the semanage error callback is invoked, describing the error. +Otherwise a non-negative integer is returned (a commit number). The same number will be returned by all other semanage object read calls until the next commit. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_set_root.3 b/selinux/libsemanage/man/man3/semanage_set_root.3 new file mode 100644 index 0000000..8125416 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_set_root.3
@@ -0,0 +1,25 @@ +.TH semanage_set_root 3 "1 June 2011" "dwalsh@redhat.com" "Libsemanage API documentation" + +.SH "NAME" +semanage_set_root, semanage_root \- SELinux Management API + +.SH "SYNOPSIS" +Set/get the alternate root directory for SELinux configuration directory. + +.B #include <semanage/handle.h> + +.B extern int semanage_set_root(const char *path); + +.B extern const char *semanage_root(void); + +.SH "DESCRIPTION" +.TP +The function semanage_set_root() sets an alternate root directory for SELinux configuration paths to be used by the semanage library. + +.SH "RETURN VALUE" +The function semanage_set_root() returns \-1 in case of failure. Otherwise, 0 is returned. + +The function semanage_root() returns the semanage root. The returned value should not be modified by the caller. + +.SH "SEE ALSO" +.BR semanage_handle_create "(3), " semanage_connect "(3), "
diff --git a/selinux/libsemanage/man/man3/semanage_seuser.3 b/selinux/libsemanage/man/man3/semanage_seuser.3 new file mode 100644 index 0000000..be0fa68 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser.3
@@ -0,0 +1,155 @@ +.TH semanage_seuser 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_seuser \- Linux UID to SELinux User Management API + +.SH "SYNOPSIS" +.B #include <semanage/seuser_record.h> +.br +.B #include <semanage/seusers_policy.h> +.br +.B #include <semanage/seusers_local.h> + +.PP +This object contains properties associated with a Unix user. Typically many Unix users are mapped to the same SELinux user. See +.BR semanage_user "(3)" +for overview of the SELinux user API. + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_seuser_create "(3)" \- +.br +create a seuser + +.HP +.BR semanage_seuser_free "(3)" \- +.br +release resources for this seuser + +.HP +.BR semanage_seuser_key_create "(3)" \- +.br +create a key, which can be used to identify a seuser + +.HP +.BR semanage_seuser_key_free "(3)" \- +.br +release resources for this seuser key + +.HP +.BR semanage_seuser_key_extract "(3)" \- +.br +create a key matching this seuser + +.HP +.BR semanage_seuser_clone "(3)" \- +.br +create an identical seuser (deep-copy clone) + +.HP +.BR semanage_seuser_compare "(3)" \- +.br +compare this seuser to the provided key + +.HP +.BR semanage_seuser_compare2 "(3)" \- +.br +compare this seuser to another + +.SH "Properties API Overview" + +.HP +.BR semanage_seuser_get_name "(3)" \- +.br +return the name of this seuser + +.HP +.BR semanage_user_set_name "(3)" \- +.br +set the name of this seuser + +.HP +.BR semanage_seuser_get_sename "(3)" \- +.br +return the name of the (SELinux) user mapped to this seuser + +.HP +.BR semanage_user_set_sename "(3)" \- +.br +set the name of the (SELinux) user mapped to this seuser + +.HP +.BR semanage_user_get_mlsrange "(3)" \- +.br +return a the range of valid MLS sensitivities and categories for this user + +.HP +.BR semanage_user_set_mlsrange "(3)" \- +.br +set the range of valid MLS sensitivities and categories for this user + +.SH "Record Store API Overview" + +.HP +.BR semanage_seuser_modify_local "(3)" \- +.br +add or update a seuser in the local store + +.HP +.BR semanage_seuser_del_local "(3)" \- +.br +delete a seuser from the local store + +.HP +.BR semanage_seuser_exists "(3)" \- +.br +check if a seuser is defined in the persistent policy + +.HP +.BR semanage_seuser_exists_local "(3)" \- +.br +check if a seuser is defined in the local store + +.HP +.BR semanage_seuser_query "(3)" \- +.br +query a seuser in the persistent policy + +.HP +.BR semanage_seuser_query_local "(3)" \- +.br +query a seuser in the local store + +.HP +.BR semanage_seuser_count "(3)" \- +.br +count the number of seusers defined in the persistent policy + +.HP +.BR semanage_seuser_count_local "(3)" \- +.br +count the number of seusers defined in the local store + +.HP +.BR semanage_seuser_iterate "(3)" \- +.br +execute a callback for each seuser in the persistent policy + +.HP +.BR semanage_seuser_iterate_local "(3)" \- +.br +execute a callback for each seuser in the local store + +.HP +.BR semanage_seuser_list "(3)" \- +.br +return an array containing all seusers in the persistent policy + +.HP +.BR semanage_seuser_list_local "(3)" \- +.br +return an array containing all seusers in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_count.3 b/selinux/libsemanage/man/man3/semanage_seuser_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_count_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_del_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_exists.3 b/selinux/libsemanage/man/man3/semanage_seuser_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_exists_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_iterate.3 b/selinux/libsemanage/man/man3/semanage_seuser_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_list.3 b/selinux/libsemanage/man/man3/semanage_seuser_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_list_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_modify_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_query.3 b/selinux/libsemanage/man/man3/semanage_seuser_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_seuser_query_local.3 b/selinux/libsemanage/man/man3/semanage_seuser_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_seuser_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_user.3 b/selinux/libsemanage/man/man3/semanage_user.3 new file mode 100644 index 0000000..6102dd5 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user.3
@@ -0,0 +1,195 @@ +.TH semanage_user 3 "16 March 2006" "ivg2@cornell.edu" "Libsemanage API documentation" + +.SH "NAME" +semanage_user \- SELinux User Management API + +.SH "SYNOPSIS" +.B #include <semanage/user_record.h> +.br +.B #include <semanage/users_policy.h> +.br +.B #include <semanage/users_local.h> + +.PP +This object contains properties associated with a SELinux user. +Typically many Unix users are mapped to the same SELinux user. See +.BR semanage_seuser "(3)" +for overview of the Unix user API. + +.PP +For details on a specific function, see its manual page. + +.SH "Record API Overview" + +.HP +.BR semanage_user_create "(3)" \- +.br +create a user + +.HP +.BR semanage_user_free "(3)" \- +.br +release resources for this user + +.HP +.BR semanage_user_key_create "(3)" \- +.br +create a key, which can be used to identify a user + +.HP +.BR semanage_user_key_free "(3)" \- +.br +release resources for this user key + +.HP +.BR semanage_user_key_extract "(3)" \- +.br +create a key matching this user + +.HP +.BR semanage_user_clone "(3)" \- +.br +create an identical user (deep-copy clone) + +.HP +.BR semanage_user_compare "(3)" \- +.br +compare this user to the provided key + +.HP +.BR semanage_user_compare2 "(3)" \- +.br +compare this user to another + +.SH "Properties API Overview" + +.HP +.BR semanage_user_get_name "(3)" \- +.br +return the name of this user + +.HP +.BR semanage_user_set_name "(3)" \- +.br +set the name of this user + +.HP +.BR semanage_user_get_prefix "(3)" \- +.br +return the labeling prefix for this user, used to control the contexts of user directories + +.HP +.BR semanage_user_set_prefix "(3)" \- +.br +set the labeling prefix for this user + +.HP +.BR semanage_user_get_mlslevel "(3)" \- +.br +return the default MLS level, which is assigned to this user at login time + +.HP +.BR semanage_user_set_mlslevel "(3)" \- +.br +set the default MLS level + +.HP +.BR semanage_user_get_mlsrange "(3)" \- +.br +return the range of valid MLS sensitivities and categories for this user + +.HP +.BR semanage_user_set_mlsrange "(3)" \- +.br +set the range of valid MLS sensitivities and categories for this user + +.HP +.BR semanage_user_add_role "(3)" \- +.br +add a role to the user's list of valid roles + +.HP +.BR semanage_user_del_role "(3)" \- +.br +remove a role from the user's list of valid roles + +.HP +.BR semanage_user_has_role "(3)" \- +.br +check if a role is valid for this user + +.HP +.BR semanage_user_get_num_roles "(3)" \- +.br +return the number of valid roles for this user + +.HP +.BR semanage_user_get_roles "(3)" \- +.br +return an array containing the roles for this user + +.HP +.BR semanage_user_set_roles "(3)" \- +set the roles for this user + +.SH "Record Store API Overview" + +.HP +.BR semanage_user_modify_local "(3)" \- +.br +add or update a user in the local store + +.HP +.BR semanage_user_del_local "(3)" \- +.br +delete a user from the local store + +.HP +.BR semanage_user_exists "(3)" \- +.br +check if a user is defined in the persistent policy + +.HP +.BR semanage_user_exists_local "(3)" \- +.br +check if a user is defined in the local store + +.HP +.BR semanage_user_query "(3)" \- +.br +query a user in the persistent policy + +.HP +.BR semanage_user_query_local "(3)" \- +.br +query a user in the local store + +.HP +.BR semanage_user_count "(3)" \- +.br +count the number of users defined in the persistent policy + +.HP +.BR semanage_user_count_local "(3)" \- +.br +count the number of users defined in the local store + +.HP +.BR semanage_user_iterate "(3)" \- +.br +execute a callback for each user in the persistent policy + +.HP +.BR semanage_user_iterate_local "(3)" \- +.br +execute a callback for each user in the local store + +.HP +.BR semanage_user_list "(3)" \- +.br +return an array containing all users in the persistent policy + +.HP +.BR semanage_user_list_local "(3)" \- +.br +return an array containing all users in the local store
diff --git a/selinux/libsemanage/man/man3/semanage_user_count.3 b/selinux/libsemanage/man/man3/semanage_user_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_count.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_count_local.3 b/selinux/libsemanage/man/man3/semanage_user_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_count_local.3
@@ -0,0 +1 @@ +.so man3/semanage_count.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_del_local.3 b/selinux/libsemanage/man/man3/semanage_user_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_del_local.3
@@ -0,0 +1 @@ +.so man3/semanage_del.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_exists.3 b/selinux/libsemanage/man/man3/semanage_user_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_exists.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_exists_local.3 b/selinux/libsemanage/man/man3/semanage_user_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_exists_local.3
@@ -0,0 +1 @@ +.so man3/semanage_exists.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_iterate.3 b/selinux/libsemanage/man/man3/semanage_user_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_iterate.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_iterate_local.3 b/selinux/libsemanage/man/man3/semanage_user_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_iterate_local.3
@@ -0,0 +1 @@ +.so man3/semanage_iterate.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_list.3 b/selinux/libsemanage/man/man3/semanage_user_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_list.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_list_local.3 b/selinux/libsemanage/man/man3/semanage_user_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_list_local.3
@@ -0,0 +1 @@ +.so man3/semanage_list.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_modify_local.3 b/selinux/libsemanage/man/man3/semanage_user_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_modify_local.3
@@ -0,0 +1 @@ +.so man3/semanage_modify.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_query.3 b/selinux/libsemanage/man/man3/semanage_user_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_query.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man3/semanage_user_query_local.3 b/selinux/libsemanage/man/man3/semanage_user_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/selinux/libsemanage/man/man3/semanage_user_query_local.3
@@ -0,0 +1 @@ +.so man3/semanage_query.3
diff --git a/selinux/libsemanage/man/man5/semanage.conf.5 b/selinux/libsemanage/man/man5/semanage.conf.5 new file mode 100644 index 0000000..8f8de55 --- /dev/null +++ b/selinux/libsemanage/man/man5/semanage.conf.5
@@ -0,0 +1,132 @@ +.TH semanage.conf "5" "September 2011" "semanage.conf" "Linux System Administration" +.SH NAME +semanage.conf \- global configuration file for the SELinux Management library +.SH DESCRIPTION +.PP +The +.BR semanage.conf +file is usually located under the directory /etc/selinux and it is used for run-time configuration of the +behavior of the SELinux Management library. + +.PP +Each line should contain a configuration parameter followed by the equal sign ("=") and then followed by the configuration value for that +parameter. Anything after the "#" symbol is ignored similarly to empty lines. + +.PP +The following parameters are allowed: + +.RS +.TP +.B module-store +Specify how the SELinux Management library should interact with the SELinux policy store. When set to "direct", the SELinux +Management library writes to the SELinux policy module store directly (this is the default setting). +Otherwise a socket path or a server name can be used for the argument. +If the argument begins with "/" (as in "/foo/bar"), it represents the path to a named socket that should be used to connect the policy management +server. +If the argument does not begin with a "/" (as in "foo.com:4242"), it should be interpreted as the name of a remote policy management server +to be used through a TCP connection (default port is 4242 unless a different one is specified after the server name using the colon to separate +the two fields). + +.TP +.B root +Specify an alternative root path to use for the store. The default is "/" + +.TP +.B store-root +Specify an alternative store_root path to use. The default is "/var/lib/selinux" + +.TP +.B compiler-directory +Specify an alternative directory that contains HLL to CIL compilers. The default value is "/usr/libexec/selinux/hll". + +.TP +.B ignore-module-cache +Whether or not to ignore the cache of CIL modules compiled from HLL. It can be set to either "true" or "false" and is set to "false" by default. +If the cache is ignored, then all CIL modules are recompiled from their HLL modules. + +.TP +.B policy-version +When generating the policy, by default +.BR semanage +will set the policy version to POLICYDB_VERSION_MAX, as defined in <sepol/policydb/policydb.h>. Change this setting if a different +version needs to be set for the policy. + +.TP +.B target-platform +The target platform to generate policies for. Valid values are "selinux" and "xen", and is set to "selinux" by default. + +.TP +.B expand-check +Whether or not to check "neverallow" rules when executing all +.BR semanage +command. It can be set to either "0" (disabled) or "1" (enabled) and by default it is enabled. There might be a large +penalty in execution time if this option is enabled. + +.TP +.B file-mode +By default the permission mode for the run-time policy files is set to 0644. + +.TP +.B save-previous +It controls whether the previous module directory is saved after a successful commit to the policy store and it can be set to +either "true" or "false". By default it is set to "false" (the previous version is deleted). + +.TP +.B save-linked +It controls whether the previously linked module is saved (with name "base.linked") after a successful commit to the policy store. +It can be set to either "true" or "false" and by default it is set to "false" (the previous module is deleted). + +.TP +.B ignoredirs +List, separated by ";", of directories to ignore when setting up users homedirs. +Some distributions use this to stop labeling /root as a homedir. + +.TP +.B usepasswd +Whether or not to enable the use getpwent() to obtain a list of home directories to label. It can be set to either "true" or "false". +By default it is set to "true". + +.TP +.B disable-genhomedircon +It controls whether or not the genhomedircon function is executed when using the +.BR semanage +command and it can be set to either "false" or "true". By default the genhomedircon functionality is enabled (equivalent +to this option set to "false"). + +.TP +.B handle-unknown +This option controls the kernel behavior for handling permissions defined in the kernel but missing from the actual policy. +It can be set to "deny", "reject" or "allow". + +.TP +.B bzip-blocksize +It should be in the range 0-9. A value of 0 means no compression. By default the bzip block size is set to 9 (actual block +size value is obtained after multiplication by 100000). + +.TP +.B bzip-small +When set to "true", the bzip algorithm shall try to reduce its system memory usage. It can be set to either "true" or "false" and +by default it is set to "false". + +.TP +.B remove-hll +When set to "true", HLL files will be removed after compilation into CIL. In order to delete HLL files already compiled into CIL, +modules will need to be recompiled with the +.BR ignore-module-cache +option set to 'true' or using the +.BR ignore-module-cache +option with semodule. The remove-hll option can be set to either "true" or "false" +and by default it is set to "false". + +Please note that since this option deletes all HLL files, an updated HLL compiler will not be able to recompile the original HLL file into CIL. +In order to compile the original HLL file into CIL, the same HLL file will need to be reinstalled. + +.SH "SEE ALSO" +.TP +semanage(8) +.PP + +.SH AUTHOR +This manual page was written by Guido Trentalancia <guido@trentalancia.com>. + +The SELinux management library was written by Tresys Technology LLC and Red Hat Inc.
diff --git a/selinux/libsemanage/src/Makefile b/selinux/libsemanage/src/Makefile new file mode 100644 index 0000000..d6c3f0f --- /dev/null +++ b/selinux/libsemanage/src/Makefile
@@ -0,0 +1,171 @@ +# Support building the Python bindings multiple times, against various Python +# runtimes (e.g. Python 2 vs Python 3) by optionally prefixing the build +# targets with "PYPREFIX": +PYTHON ?= python +PYPREFIX ?= $(notdir $(PYTHON)) +RUBY ?= ruby +RUBYPREFIX ?= $(notdir $(RUBY)) +PKG_CONFIG ?= pkg-config + +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +LIBDIR ?= $(PREFIX)/lib +SHLIBDIR ?= $(DESTDIR)/lib +INCLUDEDIR ?= $(PREFIX)/include +PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])') +PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX)) +PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER) +RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")') +RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM') +RUBYINC ?= $(shell $(PKG_CONFIG) --cflags ruby-$(RUBYLIBVER)) +RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) + +LIBBASE=$(shell basename $(LIBDIR)) + +DEFAULT_SEMANAGE_CONF_LOCATION=$(DESTDIR)/etc/selinux/semanage.conf + +ifeq ($(DEBUG),1) + export CFLAGS = -g3 -O0 -gdwarf-2 -fno-strict-aliasing -Wall -Wshadow -Werror + export LDFLAGS = -g +endif + +LEX = flex +LFLAGS = -s +YACC = bison +YFLAGS = -d + +VERSION = $(shell cat ../VERSION) +LIBVERSION = 1 + +LIBA=libsemanage.a +TARGET=libsemanage.so +LIBPC=libsemanage.pc +SWIGIF= semanageswig_python.i semanageswig_python_exception.i +SWIGRUBYIF= semanageswig_ruby.i +SWIGCOUT= semanageswig_wrap.c +SWIGRUBYCOUT= semanageswig_ruby_wrap.c +SWIGLOBJ:= $(patsubst %.c,$(PYPREFIX)%.lo,$(SWIGCOUT)) +SWIGRUBYLOBJ:= $(patsubst %.c,$(RUBYPREFIX)%.lo,$(SWIGRUBYCOUT)) +SWIGSO=$(PYPREFIX)_semanage.so +SWIGFILES=$(SWIGSO) semanage.py +SWIGRUBYSO=$(RUBYPREFIX)_semanage.so +LIBSO=$(TARGET).$(LIBVERSION) + +GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) semanageswig_python_exception.i +SRCS= $(filter-out $(GENERATED),$(wildcard *.c)) + +OBJS= $(patsubst %.c,%.o,$(SRCS)) conf-scan.o conf-parse.o +LOBJS= $(patsubst %.c,%.lo,$(SRCS)) conf-scan.lo conf-parse.lo +CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-noreturn -Wmissing-format-attribute + +SWIG_CFLAGS += -Wno-error -Wno-unused-but-set-variable -Wno-unused-variable -Wno-shadow \ + -Wno-unused-parameter + +override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE +RANLIB ?= ranlib + +SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./ + +SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ + +GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) $(wildcard conf-*.[ch]) + +all: $(LIBA) $(LIBSO) $(LIBPC) + +pywrap: all $(SWIGSO) + +rubywrap: all $(SWIGRUBYSO) + +$(SWIGLOBJ): $(SWIGCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(PYINC) -fPIC -DSHARED -c -o $@ $< + +$(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< + +$(SWIGSO): $(SWIGLOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lsemanage -L$(LIBDIR) + +$(SWIGRUBYSO): $(SWIGRUBYLOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lsemanage -L$(LIBDIR) + +$(LIBA): $(OBJS) + $(AR) rcs $@ $^ + $(RANLIB) $@ + +$(LIBSO): $(LOBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -lsepol -laudit -lselinux -lbz2 -lustr -L$(LIBDIR) -Wl,-soname,$(LIBSO),--version-script=libsemanage.map,-z,defs + ln -sf $@ $(TARGET) + +$(LIBPC): $(LIBPC).in ../VERSION + sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@ + +semanageswig_python_exception.i: ../include/semanage/semanage.h + bash exception.sh > $@ + +conf-scan.c: conf-scan.l conf-parse.h + $(LEX) $(LFLAGS) -t $< > $@ + +conf-parse.c: conf-parse.y + $(YACC) $(YFLAGS) -o $@ $< + +conf-parse.h: conf-parse.c + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.lo: %.c + $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $< + +conf-parse.o: conf-parse.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -c -o $@ $< + +conf-parse.lo: conf-parse.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -fPIC -DSHARED -c -o $@ $< + +conf-scan.o: conf-scan.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -c -o $@ $< + +conf-scan.lo: conf-scan.c + $(CC) $(filter-out -Werror, $(CFLAGS)) -fPIC -DSHARED -c -o $@ $< + +$(SWIGCOUT): $(SWIGIF) + $(SWIG) $< + +$(SWIGRUBYCOUT): $(SWIGRUBYIF) + $(SWIGRUBY) $< + +swigify: $(SWIGIF) + $(SWIG) $< + +install: all + test -d $(LIBDIR) || install -m 755 -d $(LIBDIR) + install -m 644 $(LIBA) $(LIBDIR) + install -m 755 $(LIBSO) $(LIBDIR) + test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig + install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig + test -f $(DEFAULT_SEMANAGE_CONF_LOCATION) || install -m 644 -D semanage.conf $(DEFAULT_SEMANAGE_CONF_LOCATION) + cd $(LIBDIR) && ln -sf $(LIBSO) $(TARGET) + +install-pywrap: pywrap + test -d $(PYLIBDIR)/site-packages || install -m 755 -d $(PYLIBDIR)/site-packages + install -m 755 $(SWIGSO) $(PYLIBDIR)/site-packages/_semanage.so + install -m 755 semanage.py $(PYLIBDIR)/site-packages + + +install-rubywrap: rubywrap + test -d $(RUBYINSTALL) || install -m 755 -d $(RUBYINSTALL) + install -m 755 $(SWIGRUBYSO) $(RUBYINSTALL)/semanage.so + +relabel: + /sbin/restorecon $(LIBDIR)/$(LIBSO) + +clean: + -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(SWIGLOBJ) $(SWIGSO) $(TARGET) conf-parse.c conf-parse.h conf-scan.c *.o *.lo *~ + +distclean: clean + rm -f $(SWIGCOUT) $(SWIGFILES) + +indent: + ../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch])) + +.PHONY: all clean pywrap rubywrap swigify install install-pywrap install-rubywrap distclean
diff --git a/selinux/libsemanage/src/boolean_internal.h b/selinux/libsemanage/src/boolean_internal.h new file mode 100644 index 0000000..ad12b82 --- /dev/null +++ b/selinux/libsemanage/src/boolean_internal.h
@@ -0,0 +1,44 @@ +#ifndef _SEMANAGE_BOOLEAN_INTERNAL_H_ +#define _SEMANAGE_BOOLEAN_INTERNAL_H_ + +#include <semanage/boolean_record.h> +#include <semanage/booleans_local.h> +#include <semanage/booleans_policy.h> +#include <semanage/booleans_active.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_bool_clone) + hidden_proto(semanage_bool_compare) + hidden_proto(semanage_bool_compare2) + hidden_proto(semanage_bool_create) + hidden_proto(semanage_bool_free) + hidden_proto(semanage_bool_get_name) + hidden_proto(semanage_bool_get_value) + hidden_proto(semanage_bool_key_extract) + hidden_proto(semanage_bool_key_free) + hidden_proto(semanage_bool_set_name) + hidden_proto(semanage_bool_set_value) + +/* BOOL RECORD: metod table */ +extern record_table_t SEMANAGE_BOOL_RTABLE; + +extern int bool_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void bool_file_dbase_release(dbase_config_t * dconfig); + +extern int bool_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void bool_policydb_dbase_release(dbase_config_t * dconfig); + +extern int bool_activedb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void bool_activedb_dbase_release(dbase_config_t * dconfig); + +#endif
diff --git a/selinux/libsemanage/src/boolean_record.c b/selinux/libsemanage/src/boolean_record.c new file mode 100644 index 0000000..665c022 --- /dev/null +++ b/selinux/libsemanage/src/boolean_record.c
@@ -0,0 +1,151 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_bool_t (Policy Boolean) + * Object: semanage_bool_key_t (Policy Boolean Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/boolean_record.h> + +typedef sepol_bool_t semanage_bool_t; +typedef sepol_bool_key_t semanage_bool_key_t; +#define _SEMANAGE_BOOL_DEFINED_ + +typedef semanage_bool_t record_t; +typedef semanage_bool_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "boolean_internal.h" +#include "handle.h" +#include "database.h" +#include <stdlib.h> +#include <selinux/selinux.h> + +/* Key */ +int semanage_bool_key_create(semanage_handle_t * handle, + const char *name, semanage_bool_key_t ** key) +{ + + return sepol_bool_key_create(handle->sepolh, name, key); +} + +int semanage_bool_key_extract(semanage_handle_t * handle, + const semanage_bool_t * boolean, + semanage_bool_key_t ** key) +{ + + return sepol_bool_key_extract(handle->sepolh, boolean, key); +} + +hidden_def(semanage_bool_key_extract) + +void semanage_bool_key_free(semanage_bool_key_t * key) +{ + sepol_bool_key_free(key); +} + +hidden_def(semanage_bool_key_free) + +int semanage_bool_compare(const semanage_bool_t * boolean, + const semanage_bool_key_t * key) +{ + + return sepol_bool_compare(boolean, key); +} + +hidden_def(semanage_bool_compare) + +int semanage_bool_compare2(const semanage_bool_t * boolean, + const semanage_bool_t * boolean2) +{ + + return sepol_bool_compare2(boolean, boolean2); +} + +hidden_def(semanage_bool_compare2) + +static int semanage_bool_compare2_qsort(const semanage_bool_t ** boolean, + const semanage_bool_t ** boolean2) +{ + + return sepol_bool_compare2(*boolean, *boolean2); +} + +/* Name */ +const char *semanage_bool_get_name(const semanage_bool_t * boolean) +{ + + return sepol_bool_get_name(boolean); +} + +hidden_def(semanage_bool_get_name) + +int semanage_bool_set_name(semanage_handle_t * handle, + semanage_bool_t * boolean, const char *name) +{ + int rc; + char *subname = selinux_boolean_sub(name); + rc = sepol_bool_set_name(handle->sepolh, boolean, subname); + free(subname); + return rc; +} + +hidden_def(semanage_bool_set_name) + +/* Value */ +int semanage_bool_get_value(const semanage_bool_t * boolean) +{ + + return sepol_bool_get_value(boolean); +} + +hidden_def(semanage_bool_get_value) + +void semanage_bool_set_value(semanage_bool_t * boolean, int value) +{ + + sepol_bool_set_value(boolean, value); +} + +hidden_def(semanage_bool_set_value) + +/* Create/Clone/Destroy */ +int semanage_bool_create(semanage_handle_t * handle, + semanage_bool_t ** bool_ptr) +{ + + return sepol_bool_create(handle->sepolh, bool_ptr); +} + +hidden_def(semanage_bool_create) + +int semanage_bool_clone(semanage_handle_t * handle, + const semanage_bool_t * boolean, + semanage_bool_t ** bool_ptr) +{ + + return sepol_bool_clone(handle->sepolh, boolean, bool_ptr); +} + +hidden_def(semanage_bool_clone) + +void semanage_bool_free(semanage_bool_t * boolean) +{ + + sepol_bool_free(boolean); +} + +hidden_def(semanage_bool_free) + +/* Record base functions */ +record_table_t SEMANAGE_BOOL_RTABLE = { + .create = semanage_bool_create, + .key_extract = semanage_bool_key_extract, + .key_free = semanage_bool_key_free, + .clone = semanage_bool_clone, + .compare = semanage_bool_compare, + .compare2 = semanage_bool_compare2, + .compare2_qsort = semanage_bool_compare2_qsort, + .free = semanage_bool_free, +};
diff --git a/selinux/libsemanage/src/booleans_active.c b/selinux/libsemanage/src/booleans_active.c new file mode 100644 index 0000000..0725aec --- /dev/null +++ b/selinux/libsemanage/src/booleans_active.c
@@ -0,0 +1,62 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool_key record_key_t; +typedef struct semanage_bool record_t; +#define DBASE_RECORD_DEFINED + +#include "boolean_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_bool_set_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, + const semanage_bool_t * data) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_set(handle, dconfig, key, data); +} + +int semanage_bool_query_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_bool_exists_active(semanage_handle_t * handle, + const semanage_bool_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_bool_count_active(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_bool_iterate_active(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_bool_list_active(semanage_handle_t * handle, + semanage_bool_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_active(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/booleans_activedb.c b/selinux/libsemanage/src/booleans_activedb.c new file mode 100644 index 0000000..9bcc9d7 --- /dev/null +++ b/selinux/libsemanage/src/booleans_activedb.c
@@ -0,0 +1,167 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool record_t; +typedef struct semanage_bool_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_activedb; +typedef struct dbase_activedb dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <string.h> +#include <selinux/selinux.h> +#include <semanage/handle.h> +#include "boolean_internal.h" +#include "database_activedb.h" +#include "parse_utils.h" +#include "debug.h" + +static int bool_read_list(semanage_handle_t * handle, + semanage_bool_t *** booleans, unsigned int *count) +{ + + semanage_bool_t **tmp_booleans = NULL; + unsigned int tmp_count = 0; + int i; + + char **names = NULL; + int len = 0; + + /* Fetch boolean names */ + if (security_get_boolean_names(&names, &len) < 0) { + ERR(handle, "could not get list of boolean names"); + goto err; + } + + /* Allocate a sufficiently large array */ + tmp_booleans = malloc(sizeof(semanage_bool_t *) * len); + if (tmp_booleans == NULL) + goto omem; + + /* Create records one by one */ + for (i = 0; i < len; i++) { + + int value; + + if (semanage_bool_create(handle, &tmp_booleans[i]) < 0) + goto err; + tmp_count++; + + if (semanage_bool_set_name(handle, + tmp_booleans[i], names[i]) < 0) + goto err; + + value = security_get_boolean_active(names[i]); + if (value < 0) { + ERR(handle, "could not get the value " + "for boolean %s", names[i]); + goto err; + } + + semanage_bool_set_value(tmp_booleans[i], value); + } + + /* Success */ + for (i = 0; i < len; i++) + free(names[i]); + free(names); + *booleans = tmp_booleans; + *count = tmp_count; + return STATUS_SUCCESS; + + /* Failure */ + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not read boolean list"); + for (i = 0; i < len; i++) + free(names[i]); + free(names); + for (i = 0; (unsigned int)i < tmp_count; i++) + semanage_bool_free(tmp_booleans[i]); + free(tmp_booleans); + return STATUS_ERR; +} + +static int bool_commit_list(semanage_handle_t * handle, + semanage_bool_t ** booleans, unsigned int count) +{ + + SELboolean *blist = NULL; + const char *name; + unsigned int bcount = 0; + unsigned int i; + int curvalue, newvalue; + + /* Allocate a sufficiently large array */ + blist = malloc(sizeof(SELboolean) * count); + if (blist == NULL) + goto omem; + + /* Populate array */ + for (i = 0; i < count; i++) { + name = semanage_bool_get_name(booleans[i]); + if (!name) + goto omem; + newvalue = semanage_bool_get_value(booleans[i]); + curvalue = security_get_boolean_active(name); + if (newvalue == curvalue) + continue; + blist[bcount].name = strdup(name); + if (blist[bcount].name == NULL) + goto omem; + blist[bcount].value = newvalue; + bcount++; + } + + /* Commit */ + if (security_set_boolean_list(bcount, blist, 0) < 0) { + ERR(handle, "libselinux commit failed"); + goto err; + } + + for (i = 0; i < bcount; i++) + free(blist[i].name); + free(blist); + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not commit boolean list"); + for (i = 0; i < bcount; i++) + free(blist[i].name); + free(blist); + return STATUS_ERR; +} + +/* BOOL RECORD: ACTIVEDB extension: method table */ +record_activedb_table_t SEMANAGE_BOOL_ACTIVEDB_RTABLE = { + .read_list = bool_read_list, + .commit_list = bool_commit_list, +}; + +int bool_activedb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_activedb_init(handle, + &SEMANAGE_BOOL_RTABLE, + &SEMANAGE_BOOL_ACTIVEDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_ACTIVEDB_DTABLE; + return STATUS_SUCCESS; +} + +void bool_activedb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_activedb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/booleans_file.c b/selinux/libsemanage/src/booleans_file.c new file mode 100644 index 0000000..f79d0b4 --- /dev/null +++ b/selinux/libsemanage/src/booleans_file.c
@@ -0,0 +1,130 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool record_t; +typedef struct semanage_bool_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <semanage/handle.h> +#include "boolean_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int bool_print(semanage_handle_t * handle, + semanage_bool_t * boolean, FILE * str) +{ + + const char *name = semanage_bool_get_name(boolean); + int value = semanage_bool_get_value(boolean); + + if (fprintf(str, "%s=%d\n", name, value) < 0) { + ERR(handle, "could not print boolean %s to stream", name); + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +static int bool_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_bool_t * boolean) +{ + + int value = 0; + char *str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Extract name */ + if (parse_fetch_string(handle, info, &str, '=') < 0) + goto err; + + if (semanage_bool_set_name(handle, boolean, str) < 0) + goto err; + free(str); + str = NULL; + + /* Assert = */ + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_assert_ch(handle, info, '=') < 0) + goto err; + + /* Extract value */ + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_optional_str(info, "true") != STATUS_NODATA) + value = 1; + else if (parse_optional_str(info, "TRUE") != STATUS_NODATA) + value = 1; + else if (parse_optional_str(info, "false") != STATUS_NODATA) + value = 0; + else if (parse_optional_str(info, "FALSE") != STATUS_NODATA) + value = 0; + else if (parse_fetch_int(handle, info, &value, ' ') < 0) + goto err; + + if (value != 0 && value != 1) { + ERR(handle, "invalid boolean value for \"%s\": %u " + "(%s: %u)\n%s", semanage_bool_get_name(boolean), + value, info->filename, info->lineno, info->orig_line); + goto err; + } + semanage_bool_set_value(boolean, value); + + if (parse_assert_space(handle, info) < 0) + goto err; + + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse boolean record"); + free(str); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* BOOL RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_BOOL_FILE_RTABLE = { + .parse = bool_parse, + .print = bool_print, +}; + +int bool_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_BOOL_RTABLE, + &SEMANAGE_BOOL_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void bool_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/booleans_local.c b/selinux/libsemanage/src/booleans_local.c new file mode 100644 index 0000000..508ac10 --- /dev/null +++ b/selinux/libsemanage/src/booleans_local.c
@@ -0,0 +1,70 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool_key record_key_t; +typedef struct semanage_bool record_t; +#define DBASE_RECORD_DEFINED + +#include "boolean_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_bool_modify_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, + const semanage_bool_t * data) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_bool_del_local(semanage_handle_t * handle, + const semanage_bool_key_t * key) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_bool_query_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_bool_exists_local(semanage_handle_t * handle, + const semanage_bool_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_bool_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_bool_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_bool_list_local(semanage_handle_t * handle, + semanage_bool_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/booleans_policy.c b/selinux/libsemanage/src/booleans_policy.c new file mode 100644 index 0000000..5cccf3d --- /dev/null +++ b/selinux/libsemanage/src/booleans_policy.c
@@ -0,0 +1,52 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool_key record_key_t; +typedef struct semanage_bool record_t; +#define DBASE_RECORD_DEFINED + +#include "boolean_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_bool_query(semanage_handle_t * handle, + const semanage_bool_key_t * key, + semanage_bool_t ** response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_bool_exists(semanage_handle_t * handle, + const semanage_bool_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_bool_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_bool_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_bool_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_bool_list(semanage_handle_t * handle, + semanage_bool_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_bool_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/booleans_policydb.c b/selinux/libsemanage/src/booleans_policydb.c new file mode 100644 index 0000000..6869d6c --- /dev/null +++ b/selinux/libsemanage/src/booleans_policydb.c
@@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_bool; +struct semanage_bool_key; +typedef struct semanage_bool record_t; +typedef struct semanage_bool_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <sepol/booleans.h> +#include <semanage/handle.h> +#include "boolean_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* BOOLEAN RECRORD (SEPOL): POLICYDB extension: method table */ +record_policydb_table_t SEMANAGE_BOOL_POLICYDB_RTABLE = { + .add = NULL, + .modify = NULL, +/* FIXME: these casts depend on stucts in libsepol matching structs + * in libsemanage. This is incredibly fragile - the casting gets + * rid of warnings, but is not type safe. + */ + .set = (record_policydb_table_set_t) sepol_bool_set, + .query = (record_policydb_table_query_t) sepol_bool_query, + .count = (record_policydb_table_count_t) sepol_bool_count, + .exists = (record_policydb_table_exists_t) sepol_bool_exists, + .iterate = (record_policydb_table_iterate_t) sepol_bool_iterate, +}; + +int bool_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_policydb_init(handle, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + &SEMANAGE_BOOL_RTABLE, + &SEMANAGE_BOOL_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + return STATUS_SUCCESS; +} + +void bool_policydb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_policydb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/conf-parse.y b/selinux/libsemanage/src/conf-parse.y new file mode 100644 index 0000000..b527e89 --- /dev/null +++ b/selinux/libsemanage/src/conf-parse.y
@@ -0,0 +1,562 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * James Athey <jathey@tresys.com> + * + * Copyright (C) 2004-2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ + +#include "semanage_conf.h" + +#include <sepol/policydb.h> +#include <selinux/selinux.h> +#include <semanage/handle.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern int semanage_lex(void); /* defined in conf-scan.c */ +extern int semanage_lex_destroy(void); /* defined in conf-scan.c */ +int semanage_error(const char *msg); + +extern FILE *semanage_in; +extern char *semanage_text; + +static int parse_module_store(char *arg); +static int parse_store_root_path(char *arg); +static int parse_compiler_path(char *arg); +static void semanage_conf_external_prog_destroy(external_prog_t *ep); +static int new_external_prog(external_prog_t **chain); + +static semanage_conf_t *current_conf; +static external_prog_t *new_external; +static int parse_errors; + +#define PASSIGN(p1,p2) { free(p1); p1 = p2; } + +%} + +%name-prefix "semanage_" + +%union { + int d; + char *s; +} + +%token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED TARGET_PLATFORM COMPILER_DIR IGNORE_MODULE_CACHE STORE_ROOT +%token LOAD_POLICY_START SETFILES_START SEFCONTEXT_COMPILE_START DISABLE_GENHOMEDIRCON HANDLE_UNKNOWN USEPASSWD IGNOREDIRS +%token BZIP_BLOCKSIZE BZIP_SMALL REMOVE_HLL +%token VERIFY_MOD_START VERIFY_LINKED_START VERIFY_KERNEL_START BLOCK_END +%token PROG_PATH PROG_ARGS +%token <s> ARG +%type <d> verify_start_tok + +%% + +config_file: config_line config_file + | /* empty */ + ; + +config_line: single_opt + | command_block + | verify_block + ; + +single_opt: module_store + | version + | target_platform + | store_root + | compiler_dir + | ignore_module_cache + | expand_check + | file_mode + | save_previous + | save_linked + | disable_genhomedircon + | usepasswd + | ignoredirs + | handle_unknown + | bzip_blocksize + | bzip_small + | remove_hll + ; + +module_store: MODULE_STORE '=' ARG { + if (parse_module_store($3) != 0) { + parse_errors++; + YYABORT; + } + free($3); + } + + ; + +store_root: STORE_ROOT '=' ARG { + if (parse_store_root_path($3) != 0) { + parse_errors++; + YYABORT; + } + free($3); + } + ; + +compiler_dir: COMPILER_DIR '=' ARG { + if (parse_compiler_path($3) != 0) { + parse_errors++; + YYABORT; + } + free($3); + } + ; + +ignore_module_cache: IGNORE_MODULE_CACHE '=' ARG { + if (strcasecmp($3, "true") == 0) + current_conf->ignore_module_cache = 1; + else if (strcasecmp($3, "false") == 0) + current_conf->ignore_module_cache = 0; + else { + yyerror("disable-caching can only be 'true' or 'false'"); + } + free($3); + } + ; + +version: VERSION '=' ARG { + current_conf->policyvers = atoi($3); + free($3); + if (current_conf->policyvers < sepol_policy_kern_vers_min() || + current_conf->policyvers > sepol_policy_kern_vers_max()) { + parse_errors++; + YYABORT; + } + } + ; + +target_platform: TARGET_PLATFORM '=' ARG { + if (strcasecmp($3, "selinux") == 0) + current_conf->target_platform = SEPOL_TARGET_SELINUX; + else if (strcasecmp($3, "xen") == 0) + current_conf->target_platform = SEPOL_TARGET_XEN; + else { + yyerror("target_platform can only be 'selinux' or 'xen'"); + } + free($3); + } + ; + +expand_check: EXPAND_CHECK '=' ARG { + current_conf->expand_check = atoi($3); + free($3); + } + ; + +file_mode: FILE_MODE '=' ARG { + current_conf->file_mode = strtoul($3, NULL, 8); + free($3); + } + ; + +save_previous: SAVE_PREVIOUS '=' ARG { + if (strcasecmp($3, "true") == 0) + current_conf->save_previous = 1; + else if (strcasecmp($3, "false") == 0) + current_conf->save_previous = 0; + else { + yyerror("save-previous can only be 'true' or 'false'"); + } + free($3); + } + ; + + +save_linked: SAVE_LINKED '=' ARG { + if (strcasecmp($3, "true") == 0) + current_conf->save_linked = 1; + else if (strcasecmp($3, "false") == 0) + current_conf->save_linked = 0; + else { + yyerror("save-linked can only be 'true' or 'false'"); + } + free($3); + } + ; + +disable_genhomedircon: DISABLE_GENHOMEDIRCON '=' ARG { + if (strcasecmp($3, "false") == 0) { + current_conf->disable_genhomedircon = 0; + } else if (strcasecmp($3, "true") == 0) { + current_conf->disable_genhomedircon = 1; + } else { + yyerror("disable-genhomedircon can only be 'true' or 'false'"); + } + free($3); + } + +usepasswd: USEPASSWD '=' ARG { + if (strcasecmp($3, "false") == 0) { + current_conf->usepasswd = 0; + } else if (strcasecmp($3, "true") == 0) { + current_conf->usepasswd = 1; + } else { + yyerror("usepasswd can only be 'true' or 'false'"); + } + free($3); + } + +ignoredirs: IGNOREDIRS '=' ARG { + current_conf->ignoredirs = strdup($3); + free($3); + } + +handle_unknown: HANDLE_UNKNOWN '=' ARG { + if (strcasecmp($3, "deny") == 0) { + current_conf->handle_unknown = SEPOL_DENY_UNKNOWN; + } else if (strcasecmp($3, "reject") == 0) { + current_conf->handle_unknown = SEPOL_REJECT_UNKNOWN; + } else if (strcasecmp($3, "allow") == 0) { + current_conf->handle_unknown = SEPOL_ALLOW_UNKNOWN; + } else { + yyerror("handle-unknown can only be 'deny', 'reject' or 'allow'"); + } + free($3); + } + +bzip_blocksize: BZIP_BLOCKSIZE '=' ARG { + int blocksize = atoi($3); + free($3); + if (blocksize > 9) + yyerror("bzip-blocksize can only be in the range 0-9"); + else + current_conf->bzip_blocksize = blocksize; +} + +bzip_small: BZIP_SMALL '=' ARG { + if (strcasecmp($3, "false") == 0) { + current_conf->bzip_small = 0; + } else if (strcasecmp($3, "true") == 0) { + current_conf->bzip_small = 1; + } else { + yyerror("bzip-small can only be 'true' or 'false'"); + } + free($3); +} + +remove_hll: REMOVE_HLL'=' ARG { + if (strcasecmp($3, "false") == 0) { + current_conf->remove_hll = 0; + } else if (strcasecmp($3, "true") == 0) { + current_conf->remove_hll = 1; + } else { + yyerror("remove-hll can only be 'true' or 'false'"); + } + free($3); +} + +command_block: + command_start external_opts BLOCK_END { + if (new_external->path == NULL) { + parse_errors++; + YYABORT; + } + } + ; + +command_start: + LOAD_POLICY_START { + semanage_conf_external_prog_destroy(current_conf->load_policy); + current_conf->load_policy = NULL; + if (new_external_prog(¤t_conf->load_policy) == -1) { + parse_errors++; + YYABORT; + } + } + | SETFILES_START { + semanage_conf_external_prog_destroy(current_conf->setfiles); + current_conf->setfiles = NULL; + if (new_external_prog(¤t_conf->setfiles) == -1) { + parse_errors++; + YYABORT; + } + } + | SEFCONTEXT_COMPILE_START { + semanage_conf_external_prog_destroy(current_conf->sefcontext_compile); + current_conf->sefcontext_compile = NULL; + if (new_external_prog(¤t_conf->sefcontext_compile) == -1) { + parse_errors++; + YYABORT; + } + } + ; + +verify_block: verify_start external_opts BLOCK_END { + if (new_external->path == NULL) { + parse_errors++; + YYABORT; + } + } + ; + +verify_start: verify_start_tok { + if ($1 == -1) { + parse_errors++; + YYABORT; + } + } + ; + +verify_start_tok: VERIFY_MOD_START {$$ = new_external_prog(¤t_conf->mod_prog);} + | VERIFY_LINKED_START {$$ = new_external_prog(¤t_conf->linked_prog);} + | VERIFY_KERNEL_START {$$ = new_external_prog(¤t_conf->kernel_prog);} + ; + +external_opts: external_opt external_opts + | /* empty */ + ; + +external_opt: PROG_PATH '=' ARG { PASSIGN(new_external->path, $3); } + | PROG_ARGS '=' ARG { PASSIGN(new_external->args, $3); } + ; + +%% + +static int semanage_conf_init(semanage_conf_t * conf) +{ + conf->store_type = SEMANAGE_CON_DIRECT; + conf->store_path = strdup(basename(selinux_policy_root())); + conf->ignoredirs = NULL; + conf->store_root_path = strdup("/var/lib/selinux"); + conf->compiler_directory_path = strdup("/usr/libexec/selinux/hll"); + conf->policyvers = sepol_policy_kern_vers_max(); + conf->target_platform = SEPOL_TARGET_SELINUX; + conf->expand_check = 1; + conf->handle_unknown = -1; + conf->usepasswd = 1; + conf->file_mode = 0644; + conf->bzip_blocksize = 9; + conf->bzip_small = 0; + conf->ignore_module_cache = 0; + conf->remove_hll = 0; + + conf->save_previous = 0; + conf->save_linked = 0; + + if ((conf->load_policy = + calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { + return -1; + } + + if (access("/sbin/load_policy", X_OK) == 0) { + conf->load_policy->path = strdup("/sbin/load_policy"); + } else { + conf->load_policy->path = strdup("/usr/sbin/load_policy"); + } + if (conf->load_policy->path == NULL) { + return -1; + } + conf->load_policy->args = NULL; + + if ((conf->setfiles = + calloc(1, sizeof(*(current_conf->setfiles)))) == NULL) { + return -1; + } + if (access("/sbin/setfiles", X_OK) == 0) { + conf->setfiles->path = strdup("/sbin/setfiles"); + } else { + conf->setfiles->path = strdup("/usr/sbin/setfiles"); + } + if ((conf->setfiles->path == NULL) || + (conf->setfiles->args = strdup("-q -c $@ $<")) == NULL) { + return -1; + } + + if ((conf->sefcontext_compile = + calloc(1, sizeof(*(current_conf->sefcontext_compile)))) == NULL) { + return -1; + } + if (access("/sbin/sefcontext_compile", X_OK) == 0) { + conf->sefcontext_compile->path = strdup("/sbin/sefcontext_compile"); + } else { + conf->sefcontext_compile->path = strdup("/usr/sbin/sefcontext_compile"); + } + if ((conf->sefcontext_compile->path == NULL) || + (conf->sefcontext_compile->args = strdup("$@")) == NULL) { + return -1; + } + + return 0; +} + +/* Parse a libsemanage configuration file. THIS FUNCTION IS NOT + * THREAD-SAFE! Return a newly allocated semanage_conf_t *. If the + * configuration file could be read, parse it; otherwise rely upon + * default values. If the file could not be parsed correctly or if + * out of memory return NULL. + */ +semanage_conf_t *semanage_conf_parse(const char *config_filename) +{ + if ((current_conf = calloc(1, sizeof(*current_conf))) == NULL) { + return NULL; + } + if (semanage_conf_init(current_conf) == -1) { + goto cleanup; + } + if ((semanage_in = fopen(config_filename, "r")) == NULL) { + /* configuration file does not exist or could not be + * read. THIS IS NOT AN ERROR. just rely on the + * defaults. */ + return current_conf; + } + parse_errors = 0; + semanage_parse(); + fclose(semanage_in); + semanage_lex_destroy(); + if (parse_errors != 0) { + goto cleanup; + } + return current_conf; + cleanup: + semanage_conf_destroy(current_conf); + return NULL; +} + +static void semanage_conf_external_prog_destroy(external_prog_t * ep) +{ + while (ep != NULL) { + external_prog_t *next = ep->next; + free(ep->path); + free(ep->args); + free(ep); + ep = next; + } +} + +/* Deallocates all space associated with a configuration struct, + * including the pointer itself. */ +void semanage_conf_destroy(semanage_conf_t * conf) +{ + if (conf != NULL) { + free(conf->store_path); + free(conf->ignoredirs); + free(conf->store_root_path); + free(conf->compiler_directory_path); + semanage_conf_external_prog_destroy(conf->load_policy); + semanage_conf_external_prog_destroy(conf->setfiles); + semanage_conf_external_prog_destroy(conf->sefcontext_compile); + semanage_conf_external_prog_destroy(conf->mod_prog); + semanage_conf_external_prog_destroy(conf->linked_prog); + semanage_conf_external_prog_destroy(conf->kernel_prog); + free(conf); + } +} + +int semanage_error(const char *msg) +{ + fprintf(stderr, "error parsing semanage configuration file: %s\n", msg); + parse_errors++; + return 0; +} + +/* Take the string argument for a module store. If it is exactly the + * word "direct" then have libsemanage directly manipulate the module + * store. The policy path will default to the active policy directory. + * Otherwise if it begins with a forward slash interpret it as + * an absolute path to a named socket, to which a policy server is + * listening on the other end. Otherwise treat it as the host name to + * an external server; if there is a colon in the name then everything + * after gives a port number. The default port number is 4242. + * Returns 0 on success, -1 if out of memory, -2 if a port number is + * illegal. + */ +static int parse_module_store(char *arg) +{ + /* arg is already a strdup()ed copy of yytext */ + if (arg == NULL) { + return -1; + } + free(current_conf->store_path); + if (strcmp(arg, "direct") == 0) { + current_conf->store_type = SEMANAGE_CON_DIRECT; + current_conf->store_path = + strdup(basename(selinux_policy_root())); + current_conf->server_port = -1; + } else if (*arg == '/') { + current_conf->store_type = SEMANAGE_CON_POLSERV_LOCAL; + current_conf->store_path = strdup(arg); + current_conf->server_port = -1; + } else { + char *s; + current_conf->store_type = SEMANAGE_CON_POLSERV_REMOTE; + if ((s = strchr(arg, ':')) == NULL) { + current_conf->store_path = arg; + current_conf->server_port = 4242; + } else { + char *endptr; + *s = '\0'; + current_conf->store_path = arg; + current_conf->server_port = strtol(s + 1, &endptr, 10); + if (*(s + 1) == '\0' || *endptr != '\0') { + return -2; + } + } + } + return 0; +} + +static int parse_store_root_path(char *arg) +{ + if (arg == NULL) { + return -1; + } + + free(current_conf->store_root_path); + current_conf->store_root_path = strdup(arg); + return 0; +} + +static int parse_compiler_path(char *arg) +{ + if (arg == NULL) { + return -1; + } + free(current_conf->compiler_directory_path); + current_conf->compiler_directory_path = strdup(arg); + return 0; +} + +/* Helper function; called whenever configuration file specifies + * another external program. Returns 0 on success, -1 if out of + * memory. + */ +static int new_external_prog(external_prog_t ** chain) +{ + if ((new_external = calloc(1, sizeof(*new_external))) == NULL) { + return -1; + } + /* hook this new external program to the end of the chain */ + if (*chain == NULL) { + *chain = new_external; + } else { + external_prog_t *prog = *chain; + while (prog->next != NULL) { + prog = prog->next; + } + prog->next = new_external; + } + return 0; +}
diff --git a/selinux/libsemanage/src/conf-scan.l b/selinux/libsemanage/src/conf-scan.l new file mode 100644 index 0000000..607bbf0 --- /dev/null +++ b/selinux/libsemanage/src/conf-scan.l
@@ -0,0 +1,98 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * James Athey <jathey@tresys.com> + * + * Copyright (C) 2004-2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ +#include "conf-parse.h" + +#include <ctype.h> +#include <string.h> + +static char *my_strdup (char * s); +static char *my_qstrdup (char * s); + +%} + +%option stack prefix="semanage_" +%option noinput nounput noyy_push_state noyy_pop_state noyy_top_state noyywrap + +%x arg + +%% + +#.* /* ignore comments */ +module-store return MODULE_STORE; +store-root return STORE_ROOT; +compiler-directory return COMPILER_DIR; +ignore-module-cache return IGNORE_MODULE_CACHE; +policy-version return VERSION; +target-platform return TARGET_PLATFORM; +expand-check return EXPAND_CHECK; +file-mode return FILE_MODE; +save-previous return SAVE_PREVIOUS; +save-linked return SAVE_LINKED; +disable-genhomedircon return DISABLE_GENHOMEDIRCON; +usepasswd return USEPASSWD; +ignoredirs return IGNOREDIRS; +handle-unknown return HANDLE_UNKNOWN; +bzip-blocksize return BZIP_BLOCKSIZE; +bzip-small return BZIP_SMALL; +remove-hll return REMOVE_HLL; +"[load_policy]" return LOAD_POLICY_START; +"[setfiles]" return SETFILES_START; +"[sefcontext_compile]" return SEFCONTEXT_COMPILE_START; +"[verify module]" return VERIFY_MOD_START; +"[verify linked]" return VERIFY_LINKED_START; +"[verify kernel]" return VERIFY_KERNEL_START; +"[end]" return BLOCK_END; +path return PROG_PATH; +args return PROG_ARGS; +[ \t]*=[ \t]* BEGIN arg; return '='; +[ \t\n]+ /* ignore */ +. return semanage_text[0]; +<arg>\"\" BEGIN INITIAL; semanage_lval.s = NULL; return ARG; +<arg>\".+\" BEGIN INITIAL; semanage_lval.s = my_qstrdup(semanage_text); return ARG; +<arg>.*[^\"\n] BEGIN INITIAL; semanage_lval.s = my_strdup(semanage_text); return ARG; +<arg>.|\n BEGIN INITIAL; semanage_lval.s = NULL; return ARG; + +%% + +/* Like strdup(), but also trim leading and trailing whitespace. + * Returns NULL on error. */ +static char *my_strdup(char *s) { + char *t; + while (isspace(*s)) { + s++; + } + t = s + strlen(s) - 1; + while (t >= s && isspace(*t)) { + *t = '\0'; + t--; + } + return strdup(s); +} + +/* strdup() a string sans initial and trailing characters. Does /not/ + * trim any whitespace. Returns NULL on error. */ +static char *my_qstrdup(char *s) { + s++; + s[strlen(s) - 1] = '\0'; + return strdup(s); +} +
diff --git a/selinux/libsemanage/src/context_internal.h b/selinux/libsemanage/src/context_internal.h new file mode 100644 index 0000000..729bfc8 --- /dev/null +++ b/selinux/libsemanage/src/context_internal.h
@@ -0,0 +1,11 @@ +#ifndef _SEMANAGE_CONTEXT_INTERNAL_H_ +#define _SEMANAGE_CONTEXT_INTERNAL_H_ + +#include <semanage/context_record.h> +#include "dso.h" + +hidden_proto(semanage_context_clone) + hidden_proto(semanage_context_free) + hidden_proto(semanage_context_from_string) + hidden_proto(semanage_context_to_string) +#endif
diff --git a/selinux/libsemanage/src/context_record.c b/selinux/libsemanage/src/context_record.c new file mode 100644 index 0000000..a228565 --- /dev/null +++ b/selinux/libsemanage/src/context_record.c
@@ -0,0 +1,110 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include <sepol/context_record.h> +#include "handle.h" + +typedef sepol_context_t semanage_context_t; + +#define _SEMANAGE_CONTEXT_DEFINED_ +#include "context_internal.h" + +/* User */ +const char *semanage_context_get_user(const semanage_context_t * con) +{ + + return sepol_context_get_user(con); +} + +int semanage_context_set_user(semanage_handle_t * handle, + semanage_context_t * con, const char *user) +{ + + return sepol_context_set_user(handle->sepolh, con, user); +} + +/* Role */ +const char *semanage_context_get_role(const semanage_context_t * con) +{ + + return sepol_context_get_role(con); +} + +int semanage_context_set_role(semanage_handle_t * handle, + semanage_context_t * con, const char *role) +{ + + return sepol_context_set_role(handle->sepolh, con, role); +} + +/* Type */ +const char *semanage_context_get_type(const semanage_context_t * con) +{ + + return sepol_context_get_type(con); +} + +int semanage_context_set_type(semanage_handle_t * handle, + semanage_context_t * con, const char *type) +{ + + return sepol_context_set_type(handle->sepolh, con, type); +} + +/* MLS */ +const char *semanage_context_get_mls(const semanage_context_t * con) +{ + + return sepol_context_get_mls(con); +} + +int semanage_context_set_mls(semanage_handle_t * handle, + semanage_context_t * con, const char *mls_range) +{ + + return sepol_context_set_mls(handle->sepolh, con, mls_range); +} + +/* Create/Clone/Destroy */ +int semanage_context_create(semanage_handle_t * handle, + semanage_context_t ** con_ptr) +{ + + return sepol_context_create(handle->sepolh, con_ptr); +} + +int semanage_context_clone(semanage_handle_t * handle, + const semanage_context_t * con, + semanage_context_t ** con_ptr) +{ + + return sepol_context_clone(handle->sepolh, con, con_ptr); +} + +hidden_def(semanage_context_clone) + +void semanage_context_free(semanage_context_t * con) +{ + + sepol_context_free(con); +} + +hidden_def(semanage_context_free) + +/* Parse to/from string */ +int semanage_context_from_string(semanage_handle_t * handle, + const char *str, semanage_context_t ** con) +{ + + return sepol_context_from_string(handle->sepolh, str, con); +} + +hidden_def(semanage_context_from_string) + +int semanage_context_to_string(semanage_handle_t * handle, + const semanage_context_t * con, char **str_ptr) +{ + + return sepol_context_to_string(handle->sepolh, con, str_ptr); +} + +hidden_def(semanage_context_to_string)
diff --git a/selinux/libsemanage/src/database.c b/selinux/libsemanage/src/database.c new file mode 100644 index 0000000..fc4f717 --- /dev/null +++ b/selinux/libsemanage/src/database.c
@@ -0,0 +1,201 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include <semanage/handle.h> +#include "semanage_store.h" +#include "semanage_conf.h" +#include "database.h" +#include "debug.h" + +static int assert_init(semanage_handle_t * handle, dbase_config_t * dconfig) +{ + + if (dconfig->dtable == NULL) { + + ERR(handle, + "A direct or server connection is needed " + "to use this function - please call " + "the corresponding connect() method"); + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +static int enter_ro(semanage_handle_t * handle, dbase_config_t * dconfig) +{ + + if (assert_init(handle, dconfig) < 0) + goto err; + + if (!handle->is_in_transaction && + handle->conf->store_type == SEMANAGE_CON_DIRECT) { + + if (semanage_get_active_lock(handle) < 0) { + ERR(handle, "could not get the active lock"); + goto err; + } + } + + if (dconfig->dtable->cache(handle, dconfig->dbase) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not enter read-only section"); + return STATUS_ERR; +} + +static inline int exit_ro(semanage_handle_t * handle) +{ + + int commit_num = handle->funcs->get_serial(handle); + + if (!handle->is_in_transaction && + handle->conf->store_type == SEMANAGE_CON_DIRECT) + semanage_release_active_lock(handle); + + return commit_num; +} + +static int enter_rw(semanage_handle_t * handle, dbase_config_t * dconfig) +{ + + if (assert_init(handle, dconfig) < 0) + goto err; + + if (!handle->is_in_transaction) { + ERR(handle, "this operation requires a transaction"); + goto err; + } + + if (dconfig->dtable->cache(handle, dconfig->dbase) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not enter read-write section"); + return STATUS_ERR; +} + +int dbase_modify(semanage_handle_t * handle, + dbase_config_t * dconfig, + const record_key_t * key, const record_t * data) +{ + + if (enter_rw(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->modify(handle, dconfig->dbase, key, data) < 0) + return STATUS_ERR; + + return STATUS_SUCCESS; +} + +int dbase_set(semanage_handle_t * handle, + dbase_config_t * dconfig, + const record_key_t * key, const record_t * data) +{ + + if (enter_rw(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->set(handle, dconfig->dbase, key, data) < 0) + return STATUS_ERR; + + return STATUS_SUCCESS; +} + +int dbase_del(semanage_handle_t * handle, + dbase_config_t * dconfig, const record_key_t * key) +{ + + if (enter_rw(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->del(handle, dconfig->dbase, key) < 0) + return STATUS_ERR; + + return STATUS_SUCCESS; +} + +int dbase_query(semanage_handle_t * handle, + dbase_config_t * dconfig, + const record_key_t * key, record_t ** response) +{ + + if (enter_ro(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->query(handle, dconfig->dbase, key, response) < 0) { + exit_ro(handle); + return STATUS_ERR; + } + + return exit_ro(handle); +} + +int dbase_exists(semanage_handle_t * handle, + dbase_config_t * dconfig, + const record_key_t * key, int *response) +{ + + if (enter_ro(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->exists(handle, dconfig->dbase, key, response) < 0) { + exit_ro(handle); + return STATUS_ERR; + } + + return exit_ro(handle); +} + +int dbase_count(semanage_handle_t * handle, + dbase_config_t * dconfig, unsigned int *response) +{ + + if (enter_ro(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->count(handle, dconfig->dbase, response) < 0) { + exit_ro(handle); + return STATUS_ERR; + } + + return exit_ro(handle); +} + +int dbase_iterate(semanage_handle_t * handle, + dbase_config_t * dconfig, + int (*fn) (const record_t * record, + void *fn_arg), void *fn_arg) +{ + + if (enter_ro(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->iterate(handle, dconfig->dbase, fn, fn_arg) < 0) { + exit_ro(handle); + return STATUS_ERR; + } + + return exit_ro(handle); +} + +int dbase_list(semanage_handle_t * handle, + dbase_config_t * dconfig, + record_t *** records, unsigned int *count) +{ + + if (enter_ro(handle, dconfig) < 0) + return STATUS_ERR; + + if (dconfig->dtable->list(handle, dconfig->dbase, records, count) < 0) { + exit_ro(handle); + return STATUS_ERR; + } + + return exit_ro(handle); +}
diff --git a/selinux/libsemanage/src/database.h b/selinux/libsemanage/src/database.h new file mode 100644 index 0000000..6a4a164 --- /dev/null +++ b/selinux/libsemanage/src/database.h
@@ -0,0 +1,218 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_H_ +#define _SEMANAGE_DATABASE_H_ + +#ifndef DBASE_RECORD_DEFINED +typedef void *record_t; +typedef void *record_key_t; +#define DBASE_RECORD_DEFINED +#endif + +#ifndef DBASE_DEFINED +typedef void *dbase_t; +#define DBASE_DEFINED +#endif + +/* Circular dependency */ +struct semanage_handle; + +/* RECORD interface - method table */ +typedef struct record_table { + + /* Create a record */ + int (*create) (struct semanage_handle * handle, record_t ** rec); + + /* Extract key from record */ + int (*key_extract) (struct semanage_handle * handle, + const record_t * rec, record_key_t ** key); + + /* Free record key */ + void (*key_free) (record_key_t * key); + + /* Return 0 if the record matches the key, + * -1 if the key represents a record that should + * be ordered before this record, and 1 if vice-versa */ + int (*compare) (const record_t * rec, const record_key_t * key); + + /* Return 0 if the record matches record2, + * -1 if record2 should be ordered before this record, + * and 1 if vice-versa */ + int (*compare2) (const record_t * rec, const record_t * rec2); + + /* Same as above, but dereferences the pointer first. + * This function is intenteded to be used as a qsort + * comparator. */ + int (*compare2_qsort) (const record_t ** rec, const record_t ** rec2); + + /* Deep-copy clone of this record */ + int (*clone) (struct semanage_handle * handle, + const record_t * rec, record_t ** new_rec); + + /* Deallocate record resources. Must sucessfully handle NULL. */ + void (*free) (record_t * rec); + +} record_table_t; + +/* DBASE interface - method table */ +typedef struct dbase_table { + + /* --------------- Database Functionality ----------- */ + + /* Note: In all the functions below, the key is property + * of the caller, and will not be modified by the database. + * In add/set/modify, the data is also property of the caller */ + + /* Add the specified record to + * the database. No check for duplicates is performed */ + int (*add) (struct semanage_handle * handle, + dbase_t * dbase, + const record_key_t * key, const record_t * data); + + /* Add the specified record to the + * database if it not present. + * If it's present, replace it + */ + int (*modify) (struct semanage_handle * handle, + dbase_t * dbase, + const record_key_t * key, const record_t * data); + + /* Modify the specified record in the database + * if it is present. Fail if it does not yet exist + */ + int (*set) (struct semanage_handle * handle, + dbase_t * dbase, + const record_key_t * key, const record_t * data); + + /* Delete a record */ + int (*del) (struct semanage_handle * handle, + dbase_t * dbase, const record_key_t * key); + + /* Clear all records, and leave the database in + * cached, modified state. This function does + * not require a call to cache() */ + int (*clear) (struct semanage_handle * handle, dbase_t * dbase); + + /* Retrieve a record + * + * Note: the resultant record + * becomes property of the caller, and + * must be freed accordingly */ + + int (*query) (struct semanage_handle * handle, + dbase_t * dbase, + const record_key_t * key, record_t ** response); + + /* Check if a record exists */ + int (*exists) (struct semanage_handle * handle, + dbase_t * dbase, + const record_key_t * key, int *response); + + /* Count the number of records */ + int (*count) (struct semanage_handle * handle, + dbase_t * dbase, unsigned int *response); + + /* Execute the specified handler over + * the records of this database. The handler + * can signal a successful exit by returning 1, + * an error exit by returning -1, and continue by + * returning 0 + * + * Note: The record passed into the iterate handler + * may or may not persist after the handler invocation, + * and writing to it has unspecified behavior. It *must* + * be cloned if modified, or preserved. + * + * Note: The iterate handler may not invoke any other + * semanage read functions outside a transaction. It is only + * reentrant while in transaction. The iterate handler may + * not modify the underlying database. + */ + int (*iterate) (struct semanage_handle * handle, + dbase_t * dbase, + int (*fn) (const record_t * record, + void *varg), void *fn_arg); + + /* Construct a list of all records in this database + * + * Note: The list returned becomes property of the caller, + * and must be freed accordingly. + */ + int (*list) (struct semanage_handle * handle, + dbase_t * dbase, + record_t *** records, unsigned int *count); + + /* ---------- Cache/Transaction Management ---------- */ + + /* Cache the database (if supported). + * This function must be invoked before using + * any of the database functions above. It may be invoked + * multiple times, and will update the cache if a commit + * occurred between invocations */ + int (*cache) (struct semanage_handle * handle, dbase_t * dbase); + + /* Forgets all changes that haven't been written + * to the database backend */ + void (*drop_cache) (dbase_t * dbase); + + /* Checks if there are any changes not written to the backend */ + int (*is_modified) (dbase_t * dbase); + + /* Writes the database changes to its backend */ + int (*flush) (struct semanage_handle * handle, dbase_t * dbase); + + /* ------------- Polymorphism ----------------------- */ + + /* Retrieves the record table for this database, + * which specifies how to perform basic operations + * on each record. */ + record_table_t *(*get_rtable) (dbase_t * dbase); + +} dbase_table_t; + +typedef struct dbase_config { + + /* Database state */ + dbase_t *dbase; + + /* Database methods */ + dbase_table_t *dtable; + +} dbase_config_t; + +extern int dbase_add(struct semanage_handle *handle, + dbase_config_t * dconfig, + const record_key_t * key, const record_t * data); + +extern int dbase_modify(struct semanage_handle *handle, + dbase_config_t * dconfig, + const record_key_t * key, const record_t * data); + +extern int dbase_set(struct semanage_handle *handle, + dbase_config_t * dconfig, + const record_key_t * key, const record_t * data); + +extern int dbase_del(struct semanage_handle *handle, + dbase_config_t * dconfig, const record_key_t * key); + +extern int dbase_query(struct semanage_handle *handle, + dbase_config_t * dconfig, + const record_key_t * key, record_t ** response); + +extern int dbase_exists(struct semanage_handle *handle, + dbase_config_t * dconfig, + const record_key_t * key, int *response); + +extern int dbase_count(struct semanage_handle *handle, + dbase_config_t * dconfig, unsigned int *response); + +extern int dbase_iterate(struct semanage_handle *handle, + dbase_config_t * dconfig, + int (*fn) (const record_t * record, + void *fn_arg), void *fn_arg); + +extern int dbase_list(struct semanage_handle *handle, + dbase_config_t * dconfig, + record_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/src/database_activedb.c b/selinux/libsemanage/src/database_activedb.c new file mode 100644 index 0000000..1cce0b8 --- /dev/null +++ b/selinux/libsemanage/src/database_activedb.c
@@ -0,0 +1,169 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_activedb_t (Active/Kernel) + * Extends: dbase_llist_t (Linked List) + * Implements: dbase_t (Database) + */ + +struct dbase_activedb; +typedef struct dbase_activedb dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "debug.h" +#include "handle.h" +#include "database_activedb.h" +#include "database_llist.h" + +/* ACTIVEDB dbase */ +struct dbase_activedb { + + /* Parent object - must always be + * the first field - here we are using + * a linked list to store the records */ + dbase_llist_t llist; + + /* ACTIVEDB extension */ + record_activedb_table_t *ratable; +}; + +static int dbase_activedb_cache(semanage_handle_t * handle, + dbase_activedb_t * dbase) +{ + + record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); + record_activedb_table_t *ratable = dbase->ratable; + + record_t **records = NULL; + unsigned int rcount = 0; + unsigned int i = 0; + + /* Already cached */ + if (!dbase_llist_needs_resync(handle, &dbase->llist)) + return STATUS_SUCCESS; + + /* Update cache serial */ + dbase_llist_cache_init(&dbase->llist); + if (dbase_llist_set_serial(handle, &dbase->llist) < 0) + goto err; + + /* Fetch the entire list */ + if (ratable->read_list(handle, &records, &rcount) < 0) + goto err; + + /* Add records one by one */ + for (; i < rcount; i++) { + if (dbase_llist_cache_prepend(handle, &dbase->llist, records[i]) + < 0) + goto err; + rtable->free(records[i]); + } + + free(records); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not cache active database"); + for (; i < rcount; i++) + rtable->free(records[i]); + dbase_llist_drop_cache(&dbase->llist); + free(records); + return STATUS_ERR; +} + +static int dbase_activedb_flush(semanage_handle_t * handle, + dbase_activedb_t * dbase) +{ + + record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); + record_activedb_table_t *ratable = dbase->ratable; + + record_t **records = NULL; + unsigned int rcount = 0; + unsigned int i; + + /* Not cached, or not modified - flush is not necessary */ + if (!dbase_llist_is_modified(&dbase->llist)) + return STATUS_SUCCESS; + + /* Fetch list */ + if (dbase_llist_list(handle, &dbase->llist, &records, &rcount) < 0) + goto err; + + /* Commit */ + if (ratable->commit_list(handle, records, rcount) < 0) + goto err; + + for (i = 0; i < rcount; i++) + rtable->free(records[i]); + free(records); + dbase_llist_set_modified(&dbase->llist, 0); + return STATUS_SUCCESS; + + err: + for (i = 0; i < rcount; i++) + rtable->free(records[i]); + free(records); + ERR(handle, "could not flush active database"); + return STATUS_ERR; +} + +int dbase_activedb_init(semanage_handle_t * handle, + record_table_t * rtable, + record_activedb_table_t * ratable, + dbase_activedb_t ** dbase) +{ + + dbase_activedb_t *tmp_dbase = + (dbase_activedb_t *) malloc(sizeof(dbase_activedb_t)); + + if (!tmp_dbase) + goto omem; + + tmp_dbase->ratable = ratable; + dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_ACTIVEDB_DTABLE); + + *dbase = tmp_dbase; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not initialize active database"); + free(tmp_dbase); + return STATUS_ERR; +} + +/* Release dbase resources */ +void dbase_activedb_release(dbase_activedb_t * dbase) +{ + + dbase_llist_drop_cache(&dbase->llist); + free(dbase); +} + +/* ACTIVEDB dbase - method table implementation */ +dbase_table_t SEMANAGE_ACTIVEDB_DTABLE = { + + /* Cache/Transactions */ + .cache = dbase_activedb_cache, + .drop_cache = (void *)dbase_llist_drop_cache, + .flush = dbase_activedb_flush, + .is_modified = (void *)dbase_llist_is_modified, + + /* Database API */ + .iterate = (void *)dbase_llist_iterate, + .exists = (void *)dbase_llist_exists, + .list = (void *)dbase_llist_list, + .add = (void *)dbase_llist_add, + .set = (void *)dbase_llist_set, + .del = (void *)dbase_llist_del, + .clear = (void *)dbase_llist_clear, + .modify = (void *)dbase_llist_modify, + .query = (void *)dbase_llist_query, + .count = (void *)dbase_llist_count, + + /* Polymorphism */ + .get_rtable = (void *)dbase_llist_get_rtable +};
diff --git a/selinux/libsemanage/src/database_activedb.h b/selinux/libsemanage/src/database_activedb.h new file mode 100644 index 0000000..37196c9 --- /dev/null +++ b/selinux/libsemanage/src/database_activedb.h
@@ -0,0 +1,37 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_ACTIVEDB_INTERNAL_H_ +#define _SEMANAGE_DATABASE_ACTIVEDB_INTERNAL_H_ + +#include "database.h" +#include "handle.h" + +struct dbase_activedb; +typedef struct dbase_activedb dbase_activedb_t; + +/* ACTIVEDB extension to RECORD interface - method table */ +typedef struct record_activedb_table { + + /* Read a list of records */ + int (*read_list) (semanage_handle_t * handle, + record_t *** records, unsigned int *count); + + /* Commit a list of records */ + int (*commit_list) (semanage_handle_t * handle, + record_t ** records, unsigned int count); + +} record_activedb_table_t; + +/* ACTIVEDB - initialization */ +extern int dbase_activedb_init(semanage_handle_t * handle, + record_table_t * rtable, + record_activedb_table_t * ratable, + dbase_activedb_t ** dbase); + +/* ACTIVEDB - release */ +extern void dbase_activedb_release(dbase_activedb_t * dbase); + +/* ACTIVEDB - method table implementation */ +extern dbase_table_t SEMANAGE_ACTIVEDB_DTABLE; + +#endif
diff --git a/selinux/libsemanage/src/database_file.c b/selinux/libsemanage/src/database_file.c new file mode 100644 index 0000000..a21b3ee --- /dev/null +++ b/selinux/libsemanage/src/database_file.c
@@ -0,0 +1,218 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_file_t (File) + * Extends: dbase_llist_t (Linked List) + * Implements: dbase_t (Database) + */ + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include "debug.h" +#include "handle.h" +#include "parse_utils.h" +#include "database_file.h" +#include "database_llist.h" +#include "semanage_store.h" + +/* FILE dbase */ +struct dbase_file { + + /* Parent object - must always be + * the first field - here we are using + * a linked list to store the records */ + dbase_llist_t llist; + + /* Backing path for read-only[0] and transaction[1] */ + const char *path[2]; + + /* FILE extension */ + record_file_table_t *rftable; +}; + +static int dbase_file_cache(semanage_handle_t * handle, dbase_file_t * dbase) +{ + + record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); + record_file_table_t *rftable = dbase->rftable; + + record_t *process_record = NULL; + int pstatus = STATUS_SUCCESS; + + parse_info_t *parse_info = NULL; + const char *fname = NULL; + + /* Already cached */ + if (!dbase_llist_needs_resync(handle, &dbase->llist)) + return STATUS_SUCCESS; + + /* Update cache serial */ + dbase_llist_cache_init(&dbase->llist); + if (dbase_llist_set_serial(handle, &dbase->llist) < 0) + goto err; + + fname = dbase->path[handle->is_in_transaction]; + + if (parse_init(handle, fname, NULL, &parse_info) < 0) + goto err; + + if (parse_open(handle, parse_info) < 0) + goto err; + + /* Main processing loop */ + do { + + /* Create record */ + if (rtable->create(handle, &process_record) < 0) + goto err; + + /* Parse record */ + pstatus = rftable->parse(handle, parse_info, process_record); + + /* Parse error */ + if (pstatus < 0) + goto err; + + /* End of file */ + else if (pstatus == STATUS_NODATA) + break; + + /* Prepend to cache */ + if (dbase_llist_cache_prepend(handle, &dbase->llist, + process_record) < 0) + goto err; + + rtable->free(process_record); + process_record = NULL; + + } while (pstatus != STATUS_NODATA); + + rtable->free(process_record); + parse_close(parse_info); + parse_release(parse_info); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not cache file database"); + rtable->free(process_record); + if (parse_info) { + parse_close(parse_info); + parse_release(parse_info); + } + dbase_llist_drop_cache(&dbase->llist); + return STATUS_ERR; +} + +/* Flush database to file */ +static int dbase_file_flush(semanage_handle_t * handle, dbase_file_t * dbase) +{ + + record_file_table_t *rftable = dbase->rftable; + + cache_entry_t *ptr; + const char *fname = NULL; + FILE *str = NULL; + + if (!dbase_llist_is_modified(&dbase->llist)) + return STATUS_SUCCESS; + + fname = dbase->path[handle->is_in_transaction]; + + str = fopen(fname, "w"); + if (!str) { + ERR(handle, "could not open %s for writing: %s", + fname, strerror(errno)); + goto err; + } + __fsetlocking(str, FSETLOCKING_BYCALLER); + + if (fprintf(str, "# This file is auto-generated by libsemanage\n" + "# Do not edit directly.\n\n") < 0) { + + ERR(handle, "could not write file header for %s", fname); + goto err; + } + + for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) { + if (rftable->print(handle, ptr->data, str) < 0) + goto err; + } + + dbase_llist_set_modified(&dbase->llist, 0); + fclose(str); + return STATUS_SUCCESS; + + err: + if (str != NULL) + fclose(str); + + ERR(handle, "could not flush database to file"); + return STATUS_ERR; +} + +int dbase_file_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + record_table_t * rtable, + record_file_table_t * rftable, dbase_file_t ** dbase) +{ + + dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t)); + + if (!tmp_dbase) + goto omem; + + tmp_dbase->path[0] = path_ro; + tmp_dbase->path[1] = path_rw; + tmp_dbase->rftable = rftable; + dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE); + + *dbase = tmp_dbase; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not initialize file database"); + free(tmp_dbase); + return STATUS_ERR; +} + +/* Release dbase resources */ +void dbase_file_release(dbase_file_t * dbase) +{ + + dbase_llist_drop_cache(&dbase->llist); + free(dbase); +} + +/* FILE dbase - method table implementation */ +dbase_table_t SEMANAGE_FILE_DTABLE = { + + /* Cache/Transactions */ + .cache = dbase_file_cache, + .drop_cache = (void *)dbase_llist_drop_cache, + .flush = dbase_file_flush, + .is_modified = (void *)dbase_llist_is_modified, + + /* Database API */ + .iterate = (void *)dbase_llist_iterate, + .exists = (void *)dbase_llist_exists, + .list = (void *)dbase_llist_list, + .add = (void *)dbase_llist_add, + .set = (void *)dbase_llist_set, + .del = (void *)dbase_llist_del, + .clear = (void *)dbase_llist_clear, + .modify = (void *)dbase_llist_modify, + .query = (void *)dbase_llist_query, + .count = (void *)dbase_llist_count, + + /* Polymorphism */ + .get_rtable = (void *)dbase_llist_get_rtable +};
diff --git a/selinux/libsemanage/src/database_file.h b/selinux/libsemanage/src/database_file.h new file mode 100644 index 0000000..dbd11bc --- /dev/null +++ b/selinux/libsemanage/src/database_file.h
@@ -0,0 +1,43 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_FILE_INTERNAL_H_ +#define _SEMANAGE_DATABASE_FILE_INTERNAL_H_ + +#include <stdio.h> +#include "database.h" +#include "parse_utils.h" +#include "handle.h" + +struct dbase_file; +typedef struct dbase_file dbase_file_t; + +/* FILE extension to RECORD interface - method table */ +typedef struct record_file_table { + + /* Fill record structuure based on supplied parse info. + * Parser must return STATUS_NODATA when EOF is encountered. + * Parser must handle NULL file stream correctly */ + int (*parse) (semanage_handle_t * handle, + parse_info_t * info, record_t * record); + + /* Print record to stream */ + int (*print) (semanage_handle_t * handle, + record_t * record, FILE * str); + +} record_file_table_t; + +/* FILE - initialization */ +extern int dbase_file_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + record_table_t * rtable, + record_file_table_t * rftable, + dbase_file_t ** dbase); + +/* FILE - release */ +extern void dbase_file_release(dbase_file_t * dbase); + +/* FILE - method table implementation */ +extern dbase_table_t SEMANAGE_FILE_DTABLE; + +#endif
diff --git a/selinux/libsemanage/src/database_join.c b/selinux/libsemanage/src/database_join.c new file mode 100644 index 0000000..b9b35a6 --- /dev/null +++ b/selinux/libsemanage/src/database_join.c
@@ -0,0 +1,297 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_join_t (Join) + * Extends: dbase_llist_t (Linked List) + * Implements: dbase_t (Database) + */ + +struct dbase_join; +typedef struct dbase_join dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> + +#include "user_internal.h" +#include "debug.h" +#include "handle.h" +#include "database_join.h" +#include "database_llist.h" + +/* JOIN dbase */ +struct dbase_join { + + /* Parent object - must always be + * the first field - here we are using + * a linked list to store the records */ + dbase_llist_t llist; + + /* Backing databases - for each + * thing being joined */ + dbase_config_t *join1; + dbase_config_t *join2; + + /* JOIN extension */ + record_join_table_t *rjtable; +}; + +static int dbase_join_cache(semanage_handle_t * handle, dbase_join_t * dbase) +{ + + /* Extract all the object tables information */ + dbase_t *dbase1 = dbase->join1->dbase; + dbase_t *dbase2 = dbase->join2->dbase; + dbase_table_t *dtable1 = dbase->join1->dtable; + dbase_table_t *dtable2 = dbase->join2->dtable; + record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); + record_join_table_t *rjtable = dbase->rjtable; + record_table_t *rtable1 = dtable1->get_rtable(dbase1); + record_table_t *rtable2 = dtable2->get_rtable(dbase2); + + record_key_t *rkey = NULL; + record_t *record = NULL; + record1_t **records1 = NULL; + record2_t **records2 = NULL; + unsigned int rcount1 = 0, rcount2 = 0, i = 0, j = 0; + + /* Already cached */ + if (!dbase_llist_needs_resync(handle, &dbase->llist)) + return STATUS_SUCCESS; + + /* Update cache serial */ + dbase_llist_cache_init(&dbase->llist); + if (dbase_llist_set_serial(handle, &dbase->llist) < 0) + goto err; + + /* First cache any child dbase, which must + * be the first thing done when calling dbase + * functions internally */ + if (dtable1->cache(handle, dbase1) < 0) + goto err; + if (dtable2->cache(handle, dbase2) < 0) + goto err; + + /* Fetch records */ + if (dtable1->list(handle, dbase1, &records1, &rcount1) < 0) + goto err; + if (dtable2->list(handle, dbase2, &records2, &rcount2) < 0) + goto err; + + /* Sort for quicker merge later */ + qsort(records1, rcount1, sizeof(record1_t *), + (int (*)(const void *, const void *))rtable1->compare2_qsort); + qsort(records2, rcount2, sizeof(record2_t *), + (int (*)(const void *, const void *))rtable2->compare2_qsort); + + /* Now merge into this dbase */ + while (i < rcount1 || j < rcount2) { + int rc; + + /* End of one list, or the other */ + if (i == rcount1) + rc = -1; + else if (j == rcount2) + rc = 1; + + /* Still more records to go, compare them */ + else { + if (rtable1->key_extract(handle, records1[i], &rkey) < + 0) + goto err; + + rc = rtable2->compare(records2[j], rkey); + + rtable->key_free(rkey); + rkey = NULL; + } + + /* Missing record1 data */ + if (rc < 0) { + if (rjtable->join(handle, NULL, + records2[j], &record) < 0) + goto err; + j++; + } + + /* Missing record2 data */ + else if (rc > 0) { + if (rjtable->join(handle, records1[i], + NULL, &record) < 0) + goto err; + i++; + } + + /* Both records available */ + else { + if (rjtable->join(handle, records1[i], + records2[j], &record) < 0) + goto err; + + i++; + j++; + } + + /* Add result record to database */ + if (dbase_llist_cache_prepend(handle, &dbase->llist, record) < + 0) + goto err; + + rtable->free(record); + record = NULL; + } + + /* Update cache serial */ + if (dbase_llist_set_serial(handle, &dbase->llist) < 0) + goto err; + + for (i = 0; i < rcount1; i++) + rtable1->free(records1[i]); + for (i = 0; i < rcount2; i++) + rtable2->free(records2[i]); + free(records1); + free(records2); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not cache join database"); + for (i = 0; i < rcount1; i++) + rtable1->free(records1[i]); + for (i = 0; i < rcount2; i++) + rtable2->free(records2[i]); + free(records1); + free(records2); + rtable->key_free(rkey); + rtable->free(record); + dbase_llist_drop_cache(&dbase->llist); + return STATUS_ERR; +} + +/* Flush database */ +static int dbase_join_flush(semanage_handle_t * handle, dbase_join_t * dbase) +{ + + /* Extract all the object tables information */ + dbase_t *dbase1 = dbase->join1->dbase; + dbase_t *dbase2 = dbase->join2->dbase; + dbase_table_t *dtable1 = dbase->join1->dtable; + dbase_table_t *dtable2 = dbase->join2->dtable; + record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist); + record_join_table_t *rjtable = dbase->rjtable; + record_table_t *rtable1 = dtable1->get_rtable(dbase1); + record_table_t *rtable2 = dtable2->get_rtable(dbase2); + + cache_entry_t *ptr; + record_key_t *rkey = NULL; + record1_t *record1 = NULL; + record2_t *record2 = NULL; + + /* No effect of flush */ + if (!dbase_llist_is_modified(&dbase->llist)) + return STATUS_SUCCESS; + + /* Then clear all records from the cache. + * This is *not* the same as dropping the cache - it's an explicit + * request to delete all current records. We need to do + * this because we don't store delete deltas for the join, + * so we must re-add all records from scratch */ + if (dtable1->clear(handle, dbase1) < 0) + goto err; + if (dtable2->clear(handle, dbase2) < 0) + goto err; + + /* For each record, split, and add parts into their corresponding databases */ + for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) { + + if (rtable->key_extract(handle, ptr->data, &rkey) < 0) + goto err; + + if (rjtable->split(handle, ptr->data, &record1, &record2) < 0) + goto err; + + if (dtable1->add(handle, dbase1, rkey, record1) < 0) + goto err; + + if (dtable2->add(handle, dbase2, rkey, record2) < 0) + goto err; + + rtable->key_free(rkey); + rtable1->free(record1); + rtable2->free(record2); + rkey = NULL; + record1 = NULL; + record2 = NULL; + } + + /* Note that this function does not flush the child databases, it + * leaves that decision up to higher-level code */ + + dbase_llist_set_modified(&dbase->llist, 0); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not flush join database"); + rtable->key_free(rkey); + rtable1->free(record1); + rtable2->free(record2); + return STATUS_ERR; +} + +int dbase_join_init(semanage_handle_t * handle, + record_table_t * rtable, + record_join_table_t * rjtable, + dbase_config_t * join1, + dbase_config_t * join2, dbase_t ** dbase) +{ + + dbase_join_t *tmp_dbase = malloc(sizeof(dbase_join_t)); + + if (!tmp_dbase) + goto omem; + + dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_JOIN_DTABLE); + + tmp_dbase->rjtable = rjtable; + tmp_dbase->join1 = join1; + tmp_dbase->join2 = join2; + + *dbase = tmp_dbase; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not initialize join database"); + free(tmp_dbase); + return STATUS_ERR; +} + +/* Release dbase resources */ +void dbase_join_release(dbase_join_t * dbase) +{ + + dbase_llist_drop_cache(&dbase->llist); + free(dbase); +} + +/* JOIN dbase - method table implementation */ +dbase_table_t SEMANAGE_JOIN_DTABLE = { + + /* Cache/Transactions */ + .cache = dbase_join_cache, + .drop_cache = (void *)dbase_llist_drop_cache, + .flush = dbase_join_flush, + .is_modified = (void *)dbase_llist_is_modified, + + /* Database API */ + .iterate = (void *)dbase_llist_iterate, + .exists = (void *)dbase_llist_exists, + .list = (void *)dbase_llist_list, + .add = (void *)dbase_llist_add, + .set = (void *)dbase_llist_set, + .del = (void *)dbase_llist_del, + .clear = (void *)dbase_llist_clear, + .modify = (void *)dbase_llist_modify, + .query = (void *)dbase_llist_query, + .count = (void *)dbase_llist_count, + + /* Polymorphism */ + .get_rtable = (void *)dbase_llist_get_rtable +};
diff --git a/selinux/libsemanage/src/database_join.h b/selinux/libsemanage/src/database_join.h new file mode 100644 index 0000000..d477fc4 --- /dev/null +++ b/selinux/libsemanage/src/database_join.h
@@ -0,0 +1,47 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_JOIN_INTERNAL_H_ +#define _SEMANAGE_DATABASE_JOIN_INTERNAL_H_ + +#include "database.h" +#include "handle.h" + +#ifndef DBASE_RECORD_JOIN_DEFINED +typedef void *record1_t; +typedef void *record2_t; +#define DBASE_RECORD_JOIN_DEFINED +#endif + +struct dbase_join; +typedef struct dbase_join dbase_join_t; + +/* JOIN extension to RECORD interface - method table */ +typedef struct record_join_table { + + /* Join two records together. + * One of the provided records could be NULL */ + int (*join) (semanage_handle_t * handle, + const record1_t * record1, + const record2_t * record2, record_t ** result); + + /* Splits a record into two */ + int (*split) (semanage_handle_t * handle, + const record_t * record, + record1_t ** split1, record2_t ** split2); + +} record_join_table_t; + +/* JOIN - initialization */ +extern int dbase_join_init(semanage_handle_t * handle, + record_table_t * rtable, + record_join_table_t * rjtable, + dbase_config_t * join1, + dbase_config_t * join2, dbase_join_t ** dbase); + +/* FILE - release */ +extern void dbase_join_release(dbase_join_t * dbase); + +/* JOIN - method table implementation */ +extern dbase_table_t SEMANAGE_JOIN_DTABLE; + +#endif
diff --git a/selinux/libsemanage/src/database_llist.c b/selinux/libsemanage/src/database_llist.c new file mode 100644 index 0000000..8ce2e2c --- /dev/null +++ b/selinux/libsemanage/src/database_llist.c
@@ -0,0 +1,376 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_llist_t (Linked List) + * Partially Implements: dbase_t (Database) + */ + +struct dbase_llist; +typedef struct dbase_llist dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include "debug.h" +#include "handle.h" +#include "database_llist.h" + +int dbase_llist_needs_resync(semanage_handle_t * handle, dbase_llist_t * dbase) +{ + + int cache_serial; + + if (dbase->cache_serial < 0) + return 1; + + cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) + return 1; + + if (cache_serial != dbase->cache_serial) { + dbase_llist_drop_cache(dbase); + dbase->cache_serial = -1; + return 1; + } + return 0; +} + +/* Helper for adding records to the cache */ +int dbase_llist_cache_prepend(semanage_handle_t * handle, + dbase_llist_t * dbase, const record_t * data) +{ + + /* Initialize */ + cache_entry_t *entry = (cache_entry_t *) malloc(sizeof(cache_entry_t)); + if (entry == NULL) + goto omem; + + if (dbase->rtable->clone(handle, data, &entry->data) < 0) + goto err; + + entry->prev = NULL; + entry->next = dbase->cache; + + /* Link */ + if (dbase->cache != NULL) + dbase->cache->prev = entry; + if (dbase->cache_tail == NULL) + dbase->cache_tail = entry; + dbase->cache = entry; + dbase->cache_sz++; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not cache record"); + free(entry); + return STATUS_ERR; +} + +void dbase_llist_drop_cache(dbase_llist_t * dbase) +{ + + if (dbase->cache_serial < 0) + return; + + cache_entry_t *prev, *ptr = dbase->cache; + while (ptr != NULL) { + prev = ptr; + ptr = ptr->next; + dbase->rtable->free(prev->data); + free(prev); + } + + dbase->cache_serial = -1; + dbase->modified = 0; +} + +int dbase_llist_set_serial(semanage_handle_t * handle, dbase_llist_t * dbase) +{ + + int cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) { + ERR(handle, "could not update cache serial"); + return STATUS_ERR; + } + + dbase->cache_serial = cache_serial; + return STATUS_SUCCESS; +} + +/* Helper for finding records in the cache */ +static int dbase_llist_cache_locate(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, + cache_entry_t ** entry) +{ + + cache_entry_t *ptr; + + /* Implemented in parent */ + if (dbase->dtable->cache(handle, dbase) < 0) + goto err; + + for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) { + if (!dbase->rtable->compare(ptr->data, key)) { + *entry = ptr; + return STATUS_SUCCESS; + } + } + + return STATUS_NODATA; + + err: + ERR(handle, "could not complete cache lookup"); + return STATUS_ERR; +} + +int dbase_llist_exists(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, int *response) +{ + + cache_entry_t *entry; + int status; + + status = dbase_llist_cache_locate(handle, dbase, key, &entry); + if (status < 0) + goto err; + + *response = (status != STATUS_NODATA); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not check if record exists"); + return STATUS_ERR; +} + +int dbase_llist_add(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key __attribute__ ((unused)), + const record_t * data) +{ + + if (dbase_llist_cache_prepend(handle, dbase, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not add record to the database"); + return STATUS_ERR; +} + +int dbase_llist_set(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, const record_t * data) +{ + + cache_entry_t *entry; + int status; + + status = dbase_llist_cache_locate(handle, dbase, key, &entry); + if (status < 0) + goto err; + if (status == STATUS_NODATA) { + ERR(handle, "record not found in the database"); + goto err; + } else { + dbase->rtable->free(entry->data); + if (dbase->rtable->clone(handle, data, &entry->data) < 0) + goto err; + } + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not set record value"); + return STATUS_ERR; +} + +int dbase_llist_modify(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, const record_t * data) +{ + + cache_entry_t *entry; + int status; + + status = dbase_llist_cache_locate(handle, dbase, key, &entry); + if (status < 0) + goto err; + if (status == STATUS_NODATA) { + if (dbase_llist_cache_prepend(handle, dbase, data) < 0) + goto err; + } else { + dbase->rtable->free(entry->data); + if (dbase->rtable->clone(handle, data, &entry->data) < 0) + goto err; + } + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not modify record value"); + return STATUS_ERR; +} + +hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)), + dbase_llist_t * dbase, unsigned int *response) +{ + + *response = dbase->cache_sz; + return STATUS_SUCCESS; +} + +int dbase_llist_query(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, record_t ** response) +{ + + cache_entry_t *entry; + int status; + + status = dbase_llist_cache_locate(handle, dbase, key, &entry); + if (status < 0 || status == STATUS_NODATA) + goto err; + + if (dbase->rtable->clone(handle, entry->data, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not query record value"); + return STATUS_ERR; +} + +int dbase_llist_iterate(semanage_handle_t * handle, + dbase_llist_t * dbase, + int (*fn) (const record_t * record, + void *fn_arg), void *arg) +{ + + int rc; + cache_entry_t *ptr; + + for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) { + + rc = fn(ptr->data, arg); + if (rc < 0) + goto err; + + else if (rc > 1) + break; + } + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not iterate over records"); + return STATUS_ERR; +} + +int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)), + dbase_llist_t * dbase, const record_key_t * key) +{ + + cache_entry_t *ptr, *prev = NULL; + + for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) { + if (!dbase->rtable->compare(ptr->data, key)) { + if (prev != NULL) + prev->next = ptr->next; + else + dbase->cache = ptr->next; + + if (ptr->next != NULL) + ptr->next->prev = ptr->prev; + else + dbase->cache_tail = ptr->prev; + + dbase->rtable->free(ptr->data); + dbase->cache_sz--; + free(ptr); + dbase->modified = 1; + return STATUS_SUCCESS; + } else + prev = ptr; + } + + return STATUS_SUCCESS; +} + +int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase) +{ + + int old_serial = dbase->cache_serial; + + if (dbase_llist_set_serial(handle, dbase) < 0) { + ERR(handle, "could not set serial of cleared dbase"); + return STATUS_ERR; + } + + if (old_serial >= 0) { + cache_entry_t *prev, *ptr = dbase->cache; + while (ptr != NULL) { + prev = ptr; + ptr = ptr->next; + dbase->rtable->free(prev->data); + free(prev); + } + } + + dbase->cache = NULL; + dbase->cache_tail = NULL; + dbase->cache_sz = 0; + dbase->modified = 1; + return STATUS_SUCCESS; +} + +int dbase_llist_list(semanage_handle_t * handle, + dbase_llist_t * dbase, + record_t *** records, unsigned int *count) +{ + + cache_entry_t *ptr; + record_t **tmp_records = NULL; + unsigned int tmp_count; + int i = 0; + + tmp_count = dbase->cache_sz; + if (tmp_count > 0) { + tmp_records = (record_t **) + calloc(tmp_count, sizeof(record_t *)); + + if (tmp_records == NULL) + goto omem; + + for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) { + if (dbase->rtable->clone(handle, + ptr->data, + &tmp_records[i]) < 0) + goto err; + i++; + } + } + + *records = tmp_records; + *count = tmp_count; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + if (tmp_records) { + for (; i >= 0; i--) + dbase->rtable->free(tmp_records[i]); + free(tmp_records); + } + ERR(handle, "could not allocate record array"); + return STATUS_ERR; +}
diff --git a/selinux/libsemanage/src/database_llist.h b/selinux/libsemanage/src/database_llist.h new file mode 100644 index 0000000..84994ef --- /dev/null +++ b/selinux/libsemanage/src/database_llist.h
@@ -0,0 +1,122 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_LLIST_INTERNAL_H_ +#define _SEMANAGE_DATABASE_LLIST_INTERNAL_H_ + +#include "database.h" +#include "handle.h" + +/* Representation of the database once loaded in memory */ +typedef struct cache_entry { + record_t *data; + struct cache_entry *prev; + struct cache_entry *next; +} cache_entry_t; + +/* LLIST dbase */ +typedef struct dbase_llist { + + /* Method tables */ + record_table_t *rtable; + dbase_table_t *dtable; + + /* In-memory representation (cache) */ + cache_entry_t *cache; + cache_entry_t *cache_tail; + + unsigned int cache_sz; + int cache_serial; + int modified; +} dbase_llist_t; + +/* Helpers for internal use only */ + +static inline void dbase_llist_cache_init(dbase_llist_t * dbase) +{ + + dbase->cache = NULL; + dbase->cache_tail = NULL; + dbase->cache_sz = 0; + dbase->cache_serial = -1; + dbase->modified = 0; +} + +static inline void dbase_llist_init(dbase_llist_t * dbase, + record_table_t * rtable, + dbase_table_t * dtable) +{ + + dbase->rtable = rtable; + dbase->dtable = dtable; + dbase_llist_cache_init(dbase); +} + +extern int dbase_llist_cache_prepend(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_t * data); + +extern int dbase_llist_needs_resync(semanage_handle_t * handle, + dbase_llist_t * dbase); + +extern int dbase_llist_set_serial(semanage_handle_t * handle, + dbase_llist_t * dbase); + +static inline void dbase_llist_set_modified(dbase_llist_t * dbase, int status) +{ + dbase->modified = status; +} + +/* LLIST - cache/transactions */ +extern void dbase_llist_drop_cache(dbase_llist_t * dbase); + +static inline int dbase_llist_is_modified(dbase_llist_t * dbase) +{ + + return dbase->modified; +} + +/* LLIST - polymorphism */ +static inline record_table_t *dbase_llist_get_rtable(dbase_llist_t * dbase) +{ + return dbase->rtable; +} + +/* LLIST - dbase API */ +extern int dbase_llist_exists(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, int *response); + +extern int dbase_llist_add(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, const record_t * data); + +extern int dbase_llist_set(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, const record_t * data); + +extern int dbase_llist_modify(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, const record_t * data); + +extern int dbase_llist_count(semanage_handle_t * handle, + dbase_llist_t * dbase, unsigned int *response); + +extern int dbase_llist_query(semanage_handle_t * handle, + dbase_llist_t * dbase, + const record_key_t * key, record_t ** response); + +extern int dbase_llist_iterate(semanage_handle_t * handle, + dbase_llist_t * dbase, + int (*fn) (const record_t * record, + void *fn_arg), void *arg); + +extern int dbase_llist_del(semanage_handle_t * handle, + dbase_llist_t * dbase, const record_key_t * key); + +extern int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase); + +extern int dbase_llist_list(semanage_handle_t * handle, + dbase_llist_t * dbase, + record_t *** records, unsigned int *count); + +#endif
diff --git a/selinux/libsemanage/src/database_policydb.c b/selinux/libsemanage/src/database_policydb.c new file mode 100644 index 0000000..748a6ed --- /dev/null +++ b/selinux/libsemanage/src/database_policydb.c
@@ -0,0 +1,476 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_policydb_t (Policy) + * Implements: dbase_t (Database) + */ + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <errno.h> + +#include <sepol/policydb.h> + +#include "database_policydb.h" +#include "semanage_store.h" +#include "handle.h" +#include "debug.h" + +/* POLICYDB dbase */ +struct dbase_policydb { + + /* Backing path for read-only[0] and transaction[1] */ + const char *path[2]; + + /* Base record table */ + record_table_t *rtable; + + /* Policy extensions */ + record_policydb_table_t *rptable; + + sepol_policydb_t *policydb; + + int cache_serial; + int modified; + int attached; +}; + +static void dbase_policydb_drop_cache(dbase_policydb_t * dbase) +{ + + if (dbase->cache_serial >= 0) { + sepol_policydb_free(dbase->policydb); + dbase->cache_serial = -1; + dbase->modified = 0; + } +} + +static int dbase_policydb_set_serial(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + int cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) { + ERR(handle, "could not update cache serial"); + return STATUS_ERR; + } + + dbase->cache_serial = cache_serial; + return STATUS_SUCCESS; +} + +static int dbase_policydb_needs_resync(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + int cache_serial; + + if (dbase->cache_serial < 0) + return 1; + + cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) + return 1; + + if (cache_serial != dbase->cache_serial) { + dbase_policydb_drop_cache(dbase); + dbase->cache_serial = -1; + return 1; + } + return 0; +} + +static int dbase_policydb_cache(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + FILE *fp = NULL; + sepol_policydb_t *policydb = NULL; + sepol_policy_file_t *pf = NULL; + const char *fname = NULL; + + /* Check if cache is needed */ + if (dbase->attached) + return STATUS_SUCCESS; + + if (!dbase_policydb_needs_resync(handle, dbase)) + return STATUS_SUCCESS; + + fname = dbase->path[handle->is_in_transaction]; + + if (sepol_policydb_create(&policydb) < 0) { + ERR(handle, "could not create policydb object"); + goto err; + } + + /* Try opening file + * ENOENT is not fatal - we just create an empty policydb */ + fp = fopen(fname, "rb"); + if (fp == NULL && errno != ENOENT) { + ERR(handle, "could not open %s for reading: %s", + fname, strerror(errno)); + goto err; + } + + /* If the file was opened successfully, read a policydb */ + if (fp != NULL) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + if (sepol_policy_file_create(&pf) < 0) { + ERR(handle, "could not create policy file object"); + goto err; + } + + sepol_policy_file_set_fp(pf, fp); + sepol_policy_file_set_handle(pf, handle->sepolh); + + if (sepol_policydb_read(policydb, pf) < 0) + goto err; + + sepol_policy_file_free(pf); + fclose(fp); + fp = NULL; + } + + /* Update cache serial */ + if (dbase_policydb_set_serial(handle, dbase) < 0) + goto err; + + /* Update the database policydb */ + dbase->policydb = policydb; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not cache policy database"); + if (fp) + fclose(fp); + sepol_policydb_free(policydb); + sepol_policy_file_free(pf); + return STATUS_ERR; +} + +static int dbase_policydb_flush(semanage_handle_t * handle + __attribute__ ((unused)), + dbase_policydb_t * dbase) +{ + + if (!dbase->modified) + return STATUS_SUCCESS; + + dbase->modified = 0; + + /* Stub */ + return STATUS_ERR; +} + +/* Check if modified */ +static int dbase_policydb_is_modified(dbase_policydb_t * dbase) +{ + + return dbase->modified; +} + +int dbase_policydb_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + record_table_t * rtable, + record_policydb_table_t * rptable, + dbase_policydb_t ** dbase) +{ + + dbase_policydb_t *tmp_dbase = + (dbase_policydb_t *) malloc(sizeof(dbase_policydb_t)); + + if (!tmp_dbase) + goto omem; + + tmp_dbase->path[0] = path_ro; + tmp_dbase->path[1] = path_rw; + tmp_dbase->rtable = rtable; + tmp_dbase->rptable = rptable; + tmp_dbase->policydb = NULL; + tmp_dbase->cache_serial = -1; + tmp_dbase->modified = 0; + tmp_dbase->attached = 0; + *dbase = tmp_dbase; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not initialize policy database"); + free(tmp_dbase); + + return STATUS_ERR; +} + +/* Release dbase resources */ +void dbase_policydb_release(dbase_policydb_t * dbase) +{ + + dbase_policydb_drop_cache(dbase); + free(dbase); +} + +/* Attach to a shared policydb. + * This implies drop_cache(), + * and prevents flush() and drop_cache() + * until detached. */ +void dbase_policydb_attach(dbase_policydb_t * dbase, + sepol_policydb_t * policydb) +{ + + dbase->attached = 1; + dbase_policydb_drop_cache(dbase); + dbase->policydb = policydb; +} + +/* Detach from a shared policdb. + * This implies drop_cache. */ +void dbase_policydb_detach(dbase_policydb_t * dbase) +{ + + dbase->attached = 0; + dbase->modified = 0; +} + +static int dbase_policydb_add(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, const record_t * data) +{ + + if (dbase->rptable->add(handle->sepolh, dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not add record to the database"); + return STATUS_ERR; +} + +static int dbase_policydb_set(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, const record_t * data) +{ + + if (dbase->rptable->set(handle->sepolh, dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not set record value"); + return STATUS_ERR; +} + +static int dbase_policydb_modify(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, + const record_t * data) +{ + + if (dbase->rptable->modify(handle->sepolh, + dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not modify record value"); + return STATUS_ERR; +} + +static int dbase_policydb_del(semanage_handle_t * handle + __attribute__ ((unused)), + dbase_policydb_t * dbase + __attribute__ ((unused)), + const record_key_t * key + __attribute__ ((unused))) +{ + + /* Stub */ + return STATUS_ERR; +} + +static int dbase_policydb_clear(semanage_handle_t * handle + __attribute__ ((unused)), + dbase_policydb_t * dbase + __attribute__ ((unused))) +{ + + /* Stub */ + return STATUS_ERR; +} + +static int dbase_policydb_query(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, record_t ** response) +{ + + if (dbase->rptable->query(handle->sepolh, + dbase->policydb, key, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not query record value"); + return STATUS_ERR; +} + +static int dbase_policydb_exists(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, int *response) +{ + + if (dbase->rptable->exists(handle->sepolh, + dbase->policydb, key, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not check if record exists"); + return STATUS_ERR; +} + +static int dbase_policydb_count(semanage_handle_t * handle, + dbase_policydb_t * dbase, + unsigned int *response) +{ + + if (dbase->rptable->count(handle->sepolh, + dbase->policydb, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not count the database records"); + return STATUS_ERR; +} + +static int dbase_policydb_iterate(semanage_handle_t * handle, + dbase_policydb_t * dbase, + int (*fn) (const record_t * record, + void *fn_arg), void *arg) +{ + + if (dbase->rptable->iterate(handle->sepolh, + dbase->policydb, fn, arg) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not iterate over records"); + return STATUS_ERR; +} + +struct list_handler_arg { + semanage_handle_t *handle; + record_table_t *rtable; + record_t **records; + int pos; +}; + +static int list_handler(const record_t * record, void *varg) +{ + + struct list_handler_arg *arg = (struct list_handler_arg *)varg; + + if (arg->rtable->clone(arg->handle, record, &arg->records[arg->pos]) < + 0) + return -1; + arg->pos++; + return 0; +} + +static int dbase_policydb_list(semanage_handle_t * handle, + dbase_t * dbase, + record_t *** records, unsigned int *count) +{ + + record_t **tmp_records = NULL; + unsigned int tmp_count; + struct list_handler_arg list_arg; + list_arg.pos = 0; + list_arg.rtable = dbase->rtable; + list_arg.handle = handle; + + if (dbase->rptable->count(handle->sepolh, + dbase->policydb, &tmp_count) < 0) + goto err; + + if (tmp_count > 0) { + tmp_records = (record_t **) + calloc(tmp_count, sizeof(record_t *)); + + if (tmp_records == NULL) + goto omem; + + list_arg.records = tmp_records; + + if (dbase->rptable->iterate(handle->sepolh, + dbase->policydb, list_handler, + &list_arg) < 0) { + ERR(handle, "list handler could not extract record"); + goto err; + } + } + + *records = tmp_records; + *count = tmp_count; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + if (tmp_records) { + for (; list_arg.pos >= 0; list_arg.pos--) + dbase->rtable->free(tmp_records[list_arg.pos]); + free(tmp_records); + } + ERR(handle, "could not list records"); + return STATUS_ERR; +} + +static record_table_t *dbase_policydb_get_rtable(dbase_policydb_t * dbase) +{ + + return dbase->rtable; +} + +/* POLICYDB dbase - method table implementation */ +dbase_table_t SEMANAGE_POLICYDB_DTABLE = { + + /* Cache/Transactions */ + .cache = dbase_policydb_cache, + .drop_cache = dbase_policydb_drop_cache, + .flush = dbase_policydb_flush, + .is_modified = dbase_policydb_is_modified, + + /* Database Functionality */ + .iterate = dbase_policydb_iterate, + .exists = dbase_policydb_exists, + .list = dbase_policydb_list, + .add = dbase_policydb_add, + .set = dbase_policydb_set, + .del = dbase_policydb_del, + .clear = dbase_policydb_clear, + .modify = dbase_policydb_modify, + .query = dbase_policydb_query, + .count = dbase_policydb_count, + + /* Polymorphism */ + .get_rtable = dbase_policydb_get_rtable +};
diff --git a/selinux/libsemanage/src/database_policydb.h b/selinux/libsemanage/src/database_policydb.h new file mode 100644 index 0000000..f782e0d --- /dev/null +++ b/selinux/libsemanage/src/database_policydb.h
@@ -0,0 +1,112 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_DATABASE_POLICYDB_INTERNAL_H_ +#define _SEMANAGE_DATABASE_POLICYDB_INTERNAL_H_ + +#include <sepol/handle.h> +#include <sepol/policydb.h> +#include "database.h" +#include "handle.h" + +struct dbase_policydb; +typedef struct dbase_policydb dbase_policydb_t; + +typedef int (*record_policydb_table_add_t) (sepol_handle_t * h, + sepol_policydb_t * p, + const record_key_t * rkey, + const record_t * record); + +typedef int (*record_policydb_table_modify_t) (sepol_handle_t * h, + sepol_policydb_t * p, + const record_key_t * rkey, + const record_t * record); + +typedef int (*record_policydb_table_set_t) (sepol_handle_t * h, + sepol_policydb_t * p, + const record_key_t * rkey, + const record_t * record); + +typedef int (*record_policydb_table_query_t) (sepol_handle_t * h, + const sepol_policydb_t * p, + const record_key_t * rkey, + record_t ** response); + +typedef int (*record_policydb_table_count_t) (sepol_handle_t * h, + const sepol_policydb_t * p, + unsigned int *response); + +typedef int (*record_policydb_table_exists_t) (sepol_handle_t * h, + const sepol_policydb_t * p, + const record_key_t * rkey, + int *response); + +typedef int (*record_policydb_table_iterate_t) (sepol_handle_t * h, + const sepol_policydb_t * p, + int (*fn) (const record_t * r, + void *fn_arg), + void *arg); + +/* POLICYDB extension to RECORD interface - method table */ +typedef struct record_policydb_table { + /* Add policy record */ + record_policydb_table_add_t add; + /* Modify policy record, or add if + * the key isn't found */ + record_policydb_table_modify_t modify; + /* Set policy record */ + record_policydb_table_set_t set; + /* Query policy record - return the record + * or NULL if it isn't found */ + record_policydb_table_query_t query; + /* Count records */ + record_policydb_table_count_t count; + /* Check if a record exists */ + record_policydb_table_exists_t exists; + /* Iterate over records */ + record_policydb_table_iterate_t iterate; +} record_policydb_table_t; + +/* Initialize database */ +extern int dbase_policydb_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + record_table_t * rtable, + record_policydb_table_t * rptable, + dbase_policydb_t ** dbase); + +/* Attach to a shared policydb. + * This implies drop_cache(). + * and prevents flush() and drop_cache() + * until detached. */ +extern void dbase_policydb_attach(dbase_policydb_t * dbase, + sepol_policydb_t * policydb); + +/* Detach from a shared policdb. + * This implies drop_cache. */ +extern void dbase_policydb_detach(dbase_policydb_t * dbase); + +/* Release allocated resources */ +extern void dbase_policydb_release(dbase_policydb_t * dbase); + +/* POLICYDB database - method table implementation */ +extern dbase_table_t SEMANAGE_POLICYDB_DTABLE; + +#endif
diff --git a/selinux/libsemanage/src/debug.c b/selinux/libsemanage/src/debug.c new file mode 100644 index 0000000..08a9e02 --- /dev/null +++ b/selinux/libsemanage/src/debug.c
@@ -0,0 +1,130 @@ +/* Author: Joshua Brindle <jbrindle@tresys.co + * Jason Tang <jtang@tresys.com> + * Ivan Gyurdiev <ivg2@cornell.edu> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "handle.h" +#include "debug.h" + +int semanage_msg_get_level(semanage_handle_t * handle) +{ + return handle->msg_level; +} + +hidden_def(semanage_msg_get_level) + +const char *semanage_msg_get_channel(semanage_handle_t * handle) +{ + return handle->msg_channel; +} + +hidden_def(semanage_msg_get_channel) + +const char *semanage_msg_get_fname(semanage_handle_t * handle) +{ + return handle->msg_fname; +} + +hidden_def(semanage_msg_get_fname) +#ifdef __GNUC__ + __attribute__ ((format(printf, 3, 4))) +#endif +void hidden semanage_msg_default_handler(void *varg __attribute__ ((unused)), + semanage_handle_t * handle, + const char *fmt, ...) +{ + + FILE *stream = NULL; + int errsv = 0; + + switch (semanage_msg_get_level(handle)) { + + case SEMANAGE_MSG_ERR: + stream = stderr; + errsv = errno; + break; + case SEMANAGE_MSG_WARN: + stream = stderr; + break; + default: + stream = stdout; + break; + } + + fprintf(stream, "%s.%s: ", + semanage_msg_get_channel(handle), + semanage_msg_get_fname(handle)); + + va_list ap; + va_start(ap, fmt); + vfprintf(stream, fmt, ap); + va_end(ap); + + if (errsv && errsv != ENOMEM) + fprintf(stream, " (%s).", strerror(errsv)); + + fprintf(stream, "\n"); +} + +#ifdef __GNUC__ +__attribute__ ((format(printf, 3, 4))) +#endif +void hidden semanage_msg_relay_handler(void *varg, + sepol_handle_t * sepolh, + const char *fmt, ...) +{ + va_list ap; + semanage_handle_t *sh = varg; + char buffer[1024]; + + if (!sh->msg_callback) + return; + + va_start(ap, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + sh->msg_fname = sepol_msg_get_fname(sepolh); + sh->msg_channel = sepol_msg_get_channel(sepolh); + sh->msg_level = sepol_msg_get_level(sepolh); /* XXX should map values */ + sh->msg_callback(sh->msg_callback_arg, sh, "%s", buffer); + return; +} + +extern void semanage_msg_set_callback(semanage_handle_t * handle, +#ifdef __GNUC__ + __attribute__ ((format(printf, 3, 4))) +#endif + void (*msg_callback) (void *varg, + semanage_handle_t * + handle, + const char *fmt, + ...), + void *msg_callback_arg) +{ + + handle->msg_callback = msg_callback; + handle->msg_callback_arg = msg_callback_arg; +}
diff --git a/selinux/libsemanage/src/debug.h b/selinux/libsemanage/src/debug.h new file mode 100644 index 0000000..92bfcf5 --- /dev/null +++ b/selinux/libsemanage/src/debug.h
@@ -0,0 +1,79 @@ +/* Author: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Ivan Gyurdiev <ivg2@cornell.edu> + * + * Copyright (C) 2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_INTERNAL_DEBUG_H_ +#define _SEMANAGE_INTERNAL_DEBUG_H_ + +#include <stdio.h> +#include <semanage/debug.h> +#include <sepol/debug.h> +#include "handle.h" +#include "dso.h" + +#define STATUS_SUCCESS 0 +#define STATUS_ERR -1 +#define STATUS_NODATA 1 + +#define msg_write(handle_arg, level_arg, \ + channel_arg, func_arg, ...) do { \ + \ + if ((handle_arg)->msg_callback) { \ + (handle_arg)->msg_fname = func_arg; \ + (handle_arg)->msg_channel = channel_arg; \ + (handle_arg)->msg_level = level_arg; \ + \ + (handle_arg)->msg_callback( \ + (handle_arg)->msg_callback_arg, \ + handle_arg, __VA_ARGS__); \ + } \ +} while(0) + +#define ERR(handle, ...) \ + msg_write(handle, SEMANAGE_MSG_ERR, "libsemanage", \ + __FUNCTION__, __VA_ARGS__) + +#define INFO(handle, ...) \ + msg_write(handle, SEMANAGE_MSG_INFO, "libsemanage", \ + __FUNCTION__, __VA_ARGS__) + +#define WARN(handle, ...) \ + msg_write(handle, SEMANAGE_MSG_WARN, "libsemanage", \ + __FUNCTION__, __VA_ARGS__) + +#ifdef __GNUC__ +__attribute__ ((format(printf, 3, 4))) +#endif +extern void hidden semanage_msg_default_handler(void *varg, + semanage_handle_t * handle, + const char *fmt, ...); + +#ifdef __GNUC__ +__attribute__ ((format(printf, 3, 4))) +#endif +extern void hidden semanage_msg_relay_handler(void *varg, + sepol_handle_t * handle, + const char *fmt, ...); + +hidden_proto(semanage_msg_get_channel) + hidden_proto(semanage_msg_get_fname) + hidden_proto(semanage_msg_get_level) +#endif
diff --git a/selinux/libsemanage/src/direct_api.c b/selinux/libsemanage/src/direct_api.c new file mode 100644 index 0000000..2187b65 --- /dev/null +++ b/selinux/libsemanage/src/direct_api.c
@@ -0,0 +1,2747 @@ +/* Author: Jason Tang <jtang@tresys.com> + * Christopher Ashworth <cashworth@tresys.com> + * + * Copyright (C) 2004-2006 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <sepol/module.h> +#include <sepol/handle.h> +#include <sepol/cil/cil.h> +#include <selinux/selinux.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <limits.h> +#include <errno.h> +#include <dirent.h> + +#include "user_internal.h" +#include "seuser_internal.h" +#include "port_internal.h" +#include "iface_internal.h" +#include "boolean_internal.h" +#include "fcontext_internal.h" +#include "node_internal.h" +#include "genhomedircon.h" + +#include "debug.h" +#include "handle.h" +#include "modules.h" +#include "direct_api.h" +#include "semanage_store.h" +#include "database_policydb.h" +#include "policy.h" +#include <sys/mman.h> +#include <sys/wait.h> + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +static void semanage_direct_destroy(semanage_handle_t * sh); +static int semanage_direct_disconnect(semanage_handle_t * sh); +static int semanage_direct_begintrans(semanage_handle_t * sh); +static int semanage_direct_commit(semanage_handle_t * sh); +static int semanage_direct_install(semanage_handle_t * sh, char *data, + size_t data_len, const char *module_name, const char *lang_ext); +static int semanage_direct_install_file(semanage_handle_t * sh, const char *module_name); +static int semanage_direct_extract(semanage_handle_t * sh, + semanage_module_key_t *modkey, + int extract_cil, + void **mapped_data, + size_t *data_len, + semanage_module_info_t **modinfo); +static int semanage_direct_remove(semanage_handle_t * sh, char *module_name); +static int semanage_direct_list(semanage_handle_t * sh, + semanage_module_info_t ** modinfo, + int *num_modules); +static int semanage_direct_get_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int *enabled); +static int semanage_direct_set_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int enabled); + +static int semanage_direct_get_module_info(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + semanage_module_info_t **modinfo); + +static int semanage_direct_list_all(semanage_handle_t *sh, + semanage_module_info_t **modinfo, + int *num_modules); + +static int semanage_direct_install_info(semanage_handle_t *sh, + const semanage_module_info_t *modinfo, + char *data, + size_t data_len); + +static int semanage_direct_remove_key(semanage_handle_t *sh, + const semanage_module_key_t *modkey); + +static struct semanage_policy_table direct_funcs = { + .get_serial = semanage_direct_get_serial, + .destroy = semanage_direct_destroy, + .disconnect = semanage_direct_disconnect, + .begin_trans = semanage_direct_begintrans, + .commit = semanage_direct_commit, + .install = semanage_direct_install, + .extract = semanage_direct_extract, + .install_file = semanage_direct_install_file, + .remove = semanage_direct_remove, + .list = semanage_direct_list, + .get_enabled = semanage_direct_get_enabled, + .set_enabled = semanage_direct_set_enabled, + .get_module_info = semanage_direct_get_module_info, + .list_all = semanage_direct_list_all, + .install_info = semanage_direct_install_info, + .remove_key = semanage_direct_remove_key, +}; + +int semanage_direct_is_managed(semanage_handle_t * sh) +{ + if (semanage_check_init(sh, sh->conf->store_root_path)) + goto err; + + if (semanage_access_check(sh) < 0) + return 0; + + return 1; + + err: + ERR(sh, "could not check whether policy is managed"); + return STATUS_ERR; +} + +/* Check that the module store exists, creating it if necessary. + */ +int semanage_direct_connect(semanage_handle_t * sh) +{ + const char *path; + + if (semanage_check_init(sh, sh->conf->store_root_path)) + goto err; + + if (sh->create_store) + if (semanage_create_store(sh, 1)) + goto err; + + if (semanage_access_check(sh) < SEMANAGE_CAN_READ) + goto err; + + sh->u.direct.translock_file_fd = -1; + sh->u.direct.activelock_file_fd = -1; + + /* set up function pointers */ + sh->funcs = &direct_funcs; + + /* Object databases: local modifications */ + if (user_base_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_USERS_BASE_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_BASE_LOCAL), + semanage_user_base_dbase_local(sh)) < 0) + goto err; + + if (user_extra_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_USERS_EXTRA_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_EXTRA_LOCAL), + semanage_user_extra_dbase_local(sh)) < 0) + goto err; + + if (user_join_dbase_init(sh, + semanage_user_base_dbase_local(sh), + semanage_user_extra_dbase_local(sh), + semanage_user_dbase_local(sh)) < 0) + goto err; + + if (port_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_PORTS_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_PORTS_LOCAL), + semanage_port_dbase_local(sh)) < 0) + goto err; + + if (iface_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_INTERFACES_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_INTERFACES_LOCAL), + semanage_iface_dbase_local(sh)) < 0) + goto err; + + if (bool_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_BOOLEANS_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_BOOLEANS_LOCAL), + semanage_bool_dbase_local(sh)) < 0) + goto err; + + if (fcontext_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_LOCAL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL), + semanage_fcontext_dbase_local(sh)) < 0) + goto err; + + if (seuser_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_SEUSERS_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_SEUSERS_LOCAL), + semanage_seuser_dbase_local(sh)) < 0) + goto err; + + if (node_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_NODES_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_NODES_LOCAL), + semanage_node_dbase_local(sh)) < 0) + goto err; + + /* Object databases: local modifications + policy */ + if (user_base_policydb_dbase_init(sh, + semanage_user_base_dbase_policy(sh)) < + 0) + goto err; + + if (user_extra_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_USERS_EXTRA), + semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_EXTRA), + semanage_user_extra_dbase_policy(sh)) < + 0) + goto err; + + if (user_join_dbase_init(sh, + semanage_user_base_dbase_policy(sh), + semanage_user_extra_dbase_policy(sh), + semanage_user_dbase_policy(sh)) < 0) + goto err; + + if (port_policydb_dbase_init(sh, semanage_port_dbase_policy(sh)) < 0) + goto err; + + if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0) + goto err; + + if (bool_policydb_dbase_init(sh, semanage_bool_dbase_policy(sh)) < 0) + goto err; + + if (fcontext_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), + semanage_fcontext_dbase_policy(sh)) < 0) + goto err; + + if (seuser_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_SEUSERS), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS), + semanage_seuser_dbase_policy(sh)) < 0) + goto err; + + if (node_policydb_dbase_init(sh, semanage_node_dbase_policy(sh)) < 0) + goto err; + + /* Active kernel policy */ + if (bool_activedb_dbase_init(sh, semanage_bool_dbase_active(sh)) < 0) + goto err; + + /* set the disable dontaudit value */ + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_DISABLE_DONTAUDIT); + if (access(path, F_OK) == 0) + sepol_set_disable_dontaudit(sh->sepolh, 1); + else + sepol_set_disable_dontaudit(sh->sepolh, 0); + + return STATUS_SUCCESS; + + err: + ERR(sh, "could not establish direct connection"); + return STATUS_ERR; +} + +static void semanage_direct_destroy(semanage_handle_t * sh + __attribute__ ((unused))) +{ + /* do nothing */ +} + +static int semanage_direct_disconnect(semanage_handle_t * sh) +{ + /* destroy transaction */ + if (sh->is_in_transaction) { + /* destroy sandbox */ + if (semanage_remove_directory + (semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)) < 0) { + ERR(sh, "Could not cleanly remove sandbox %s.", + semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); + return -1; + } + if (semanage_remove_directory + (semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)) < 0) { + ERR(sh, "Could not cleanly remove tmp %s.", + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)); + return -1; + } + semanage_release_trans_lock(sh); + } + + /* Release object databases: local modifications */ + user_base_file_dbase_release(semanage_user_base_dbase_local(sh)); + user_extra_file_dbase_release(semanage_user_extra_dbase_local(sh)); + user_join_dbase_release(semanage_user_dbase_local(sh)); + port_file_dbase_release(semanage_port_dbase_local(sh)); + iface_file_dbase_release(semanage_iface_dbase_local(sh)); + bool_file_dbase_release(semanage_bool_dbase_local(sh)); + fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh)); + seuser_file_dbase_release(semanage_seuser_dbase_local(sh)); + node_file_dbase_release(semanage_node_dbase_local(sh)); + + /* Release object databases: local modifications + policy */ + user_base_policydb_dbase_release(semanage_user_base_dbase_policy(sh)); + user_extra_file_dbase_release(semanage_user_extra_dbase_policy(sh)); + user_join_dbase_release(semanage_user_dbase_policy(sh)); + port_policydb_dbase_release(semanage_port_dbase_policy(sh)); + iface_policydb_dbase_release(semanage_iface_dbase_policy(sh)); + bool_policydb_dbase_release(semanage_bool_dbase_policy(sh)); + fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh)); + seuser_file_dbase_release(semanage_seuser_dbase_policy(sh)); + node_policydb_dbase_release(semanage_node_dbase_policy(sh)); + + /* Release object databases: active kernel policy */ + bool_activedb_dbase_release(semanage_bool_dbase_active(sh)); + + return 0; +} + +static int semanage_direct_begintrans(semanage_handle_t * sh) +{ + + if (semanage_access_check(sh) != SEMANAGE_CAN_WRITE) { + return -1; + } + if (semanage_get_trans_lock(sh) < 0) { + return -1; + } + if ((semanage_make_sandbox(sh)) < 0) { + return -1; + } + if ((semanage_make_final(sh)) < 0) { + return -1; + } + return 0; +} + +/********************* utility functions *********************/ + +#include <stdlib.h> +#include <bzlib.h> +#include <string.h> +#include <sys/sendfile.h> + +/* bzip() a data to a file, returning the total number of compressed bytes + * in the file. Returns -1 if file could not be compressed. */ +static ssize_t bzip(semanage_handle_t *sh, const char *filename, char *data, + size_t num_bytes) +{ + BZFILE* b; + size_t size = 1<<16; + int bzerror; + size_t total = 0; + size_t len = 0; + FILE *f; + + if ((f = fopen(filename, "wb")) == NULL) { + return -1; + } + + if (!sh->conf->bzip_blocksize) { + if (fwrite(data, 1, num_bytes, f) < num_bytes) { + fclose(f); + return -1; + } + fclose(f); + return num_bytes; + } + + b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0); + if (bzerror != BZ_OK) { + BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 ); + return -1; + } + + while ( num_bytes > total ) { + if (num_bytes - total > size) { + len = size; + } else { + len = num_bytes - total; + } + BZ2_bzWrite ( &bzerror, b, &data[total], len ); + if (bzerror == BZ_IO_ERROR) { + BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 ); + return -1; + } + total += len; + } + + BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 ); + fclose(f); + if (bzerror == BZ_IO_ERROR) { + return -1; + } + return total; +} + +#define BZ2_MAGICSTR "BZh" +#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1) + +/* bunzip() a file to '*data', returning the total number of uncompressed bytes + * in the file. Returns -1 if file could not be decompressed. */ +ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data) +{ + BZFILE* b = NULL; + size_t nBuf; + char* buf = NULL; + size_t size = 1<<18; + size_t bufsize = size; + int bzerror; + size_t total=0; + char* uncompress = NULL; + char* tmpalloc = NULL; + int ret = -1; + + buf = malloc(bufsize); + if (buf == NULL) { + ERR(sh, "Failure allocating memory."); + goto exit; + } + + /* Check if the file is bzipped */ + bzerror = fread(buf, 1, BZ2_MAGICLEN, f); + rewind(f); + if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) { + goto exit; + } + + b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 ); + if ( bzerror != BZ_OK ) { + ERR(sh, "Failure opening bz2 archive."); + goto exit; + } + + uncompress = malloc(size); + if (uncompress == NULL) { + ERR(sh, "Failure allocating memory."); + goto exit; + } + + while ( bzerror == BZ_OK) { + nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize); + if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) { + if (total + nBuf > size) { + size *= 2; + tmpalloc = realloc(uncompress, size); + if (tmpalloc == NULL) { + ERR(sh, "Failure allocating memory."); + goto exit; + } + uncompress = tmpalloc; + } + memcpy(&uncompress[total], buf, nBuf); + total += nBuf; + } + } + if ( bzerror != BZ_STREAM_END ) { + ERR(sh, "Failure reading bz2 archive."); + goto exit; + } + + ret = total; + *data = uncompress; + +exit: + BZ2_bzReadClose ( &bzerror, b ); + free(buf); + if ( ret < 0 ) { + free(uncompress); + } + return ret; +} + +/* mmap() a file to '*data', + * If the file is bzip compressed map_file will uncompress + * the file into '*data'. + * Returns the total number of bytes in memory . + * Returns -1 if file could not be opened or mapped. */ +static ssize_t map_file(semanage_handle_t *sh, const char *path, char **data, + int *compressed) +{ + ssize_t size = -1; + char *uncompress; + int fd = -1; + FILE *file = NULL; + + fd = open(path, O_RDONLY); + if (fd == -1) { + ERR(sh, "Unable to open %s\n", path); + return -1; + } + + file = fdopen(fd, "r"); + if (file == NULL) { + ERR(sh, "Unable to open %s\n", path); + close(fd); + return -1; + } + + if ((size = bunzip(sh, file, &uncompress)) > 0) { + *data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (*data == MAP_FAILED) { + free(uncompress); + fclose(file); + return -1; + } else { + memcpy(*data, uncompress, size); + } + free(uncompress); + *compressed = 1; + } else { + struct stat sb; + if (fstat(fd, &sb) == -1 || + (*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == + MAP_FAILED) { + size = -1; + } else { + size = sb.st_size; + } + *compressed = 0; + } + + fclose(file); + + return size; +} + +/* Writes a block of data to a file. Returns 0 on success, -1 on + * error. */ +static int write_file(semanage_handle_t * sh, + const char *filename, char *data, size_t num_bytes) +{ + int out; + + if ((out = + open(filename, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR)) == -1) { + ERR(sh, "Could not open %s for writing.", filename); + return -1; + } + if (write(out, data, num_bytes) == -1) { + ERR(sh, "Error while writing to %s.", filename); + close(out); + return -1; + } + close(out); + return 0; +} + +static int semanage_direct_update_user_extra(semanage_handle_t * sh, cil_db_t *cildb) +{ + const char *ofilename = NULL; + int retval = -1; + char *data = NULL; + size_t size = 0; + + dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh); + + retval = cil_userprefixes_to_string(cildb, &data, &size); + if (retval != SEPOL_OK) { + goto cleanup; + } + + if (size > 0) { + ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA); + if (ofilename == NULL) { + return retval; + } + retval = write_file(sh, ofilename, data, size); + if (retval < 0) + return retval; + + pusers_extra->dtable->drop_cache(pusers_extra->dbase); + + } else { + retval = pusers_extra->dtable->clear(sh, pusers_extra->dbase); + } + +cleanup: + free(data); + + return retval; +} + +static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb) +{ + const char *ofilename = NULL; + int retval = -1; + char *data = NULL; + size_t size = 0; + + dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh); + + retval = cil_selinuxusers_to_string(cildb, &data, &size); + if (retval != SEPOL_OK) { + goto cleanup; + } + + if (size > 0) { + ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); + if (ofilename == NULL) { + return -1; + } + retval = write_file(sh, ofilename, data, size); + + pseusers->dtable->drop_cache(pseusers->dbase); + } else { + retval = pseusers->dtable->clear(sh, pseusers->dbase); + } + +cleanup: + free(data); + + return retval; +} + +static int read_from_pipe_to_data(semanage_handle_t *sh, size_t initial_len, int fd, char **out_data_read, size_t *out_read_len) +{ + size_t max_len = initial_len; + size_t read_len = 0; + size_t data_read_len = 0; + char *data_read = NULL; + + if (max_len <= 0) { + max_len = 1; + } + data_read = malloc(max_len * sizeof(*data_read)); + if (data_read == NULL) { + ERR(sh, "Failed to malloc, out of memory.\n"); + return -1; + } + + while ((read_len = read(fd, data_read + data_read_len, max_len - data_read_len)) > 0) { + data_read_len += read_len; + if (data_read_len == max_len) { + max_len *= 2; + data_read = realloc(data_read, max_len); + if (data_read == NULL) { + ERR(sh, "Failed to realloc, out of memory.\n"); + return -1; + } + } + } + + *out_read_len = data_read_len; + *out_data_read = data_read; + + return 0; +} + +static int semanage_pipe_data(semanage_handle_t *sh, char *path, char *in_data, size_t in_data_len, char **out_data, size_t *out_data_len, char **err_data, size_t *err_data_len) +{ + int input_fd[2]; + int output_fd[2]; + int err_fd[2]; + pid_t pid; + char *data_read = NULL; + char *err_data_read = NULL; + int retval; + int status = 0; + size_t initial_len; + size_t data_read_len = 0; + size_t err_data_read_len = 0; + struct sigaction old_signal; + struct sigaction new_signal; + new_signal.sa_handler = SIG_IGN; + sigemptyset(&new_signal.sa_mask); + new_signal.sa_flags = 0; + /* This is needed in case the read end of input_fd is closed causing a SIGPIPE signal to be sent. + * If SIGPIPE is not caught, the signal will cause semanage to terminate immediately. The sigaction below + * creates a new_signal that ignores SIGPIPE allowing the write to exit cleanly. + * + * Another sigaction is called in cleanup to restore the original behavior when a SIGPIPE is received. + */ + sigaction(SIGPIPE, &new_signal, &old_signal); + + retval = pipe(input_fd); + if (retval == -1) { + ERR(sh, "Unable to create pipe for input pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = pipe(output_fd); + if (retval == -1) { + ERR(sh, "Unable to create pipe for output pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = pipe(err_fd); + if (retval == -1) { + ERR(sh, "Unable to create pipe for error pipe: %s\n", strerror(errno)); + goto cleanup; + } + + pid = fork(); + if (pid == -1) { + ERR(sh, "Unable to fork from parent: %s.", strerror(errno)); + retval = -1; + goto cleanup; + } else if (pid == 0) { + retval = dup2(input_fd[PIPE_READ], STDIN_FILENO); + if (retval == -1) { + ERR(sh, "Unable to dup2 input pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = dup2(output_fd[PIPE_WRITE], STDOUT_FILENO); + if (retval == -1) { + ERR(sh, "Unable to dup2 output pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = dup2(err_fd[PIPE_WRITE], STDERR_FILENO); + if (retval == -1) { + ERR(sh, "Unable to dup2 error pipe: %s\n", strerror(errno)); + goto cleanup; + } + + retval = close(input_fd[PIPE_WRITE]); + if (retval == -1) { + ERR(sh, "Unable to close input pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = close(output_fd[PIPE_READ]); + if (retval == -1) { + ERR(sh, "Unable to close output pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = close(err_fd[PIPE_READ]); + if (retval == -1) { + ERR(sh, "Unable to close error pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = execl(path, path, NULL); + if (retval == -1) { + ERR(sh, "Unable to execute %s : %s\n", path, strerror(errno)); + _exit(EXIT_FAILURE); + } + } else { + retval = close(input_fd[PIPE_READ]); + input_fd[PIPE_READ] = -1; + if (retval == -1) { + ERR(sh, "Unable to close read end of input pipe: %s\n", strerror(errno)); + goto cleanup; + } + + retval = close(output_fd[PIPE_WRITE]); + output_fd[PIPE_WRITE] = -1; + if (retval == -1) { + ERR(sh, "Unable to close write end of output pipe: %s\n", strerror(errno)); + goto cleanup; + } + + retval = close(err_fd[PIPE_WRITE]); + err_fd[PIPE_WRITE] = -1; + if (retval == -1) { + ERR(sh, "Unable to close write end of error pipe: %s\n", strerror(errno)); + goto cleanup; + } + + retval = write(input_fd[PIPE_WRITE], in_data, in_data_len); + if (retval == -1) { + ERR(sh, "Failed to write data to input pipe: %s\n", strerror(errno)); + goto cleanup; + } + retval = close(input_fd[PIPE_WRITE]); + input_fd[PIPE_WRITE] = -1; + if (retval == -1) { + ERR(sh, "Unable to close write end of input pipe: %s\n", strerror(errno)); + goto cleanup; + } + + initial_len = 1 << 17; + retval = read_from_pipe_to_data(sh, initial_len, output_fd[PIPE_READ], &data_read, &data_read_len); + if (retval != 0) { + goto cleanup; + } + retval = close(output_fd[PIPE_READ]); + output_fd[PIPE_READ] = -1; + if (retval == -1) { + ERR(sh, "Unable to close read end of output pipe: %s\n", strerror(errno)); + goto cleanup; + } + + initial_len = 1 << 9; + retval = read_from_pipe_to_data(sh, initial_len, err_fd[PIPE_READ], &err_data_read, &err_data_read_len); + if (retval != 0) { + goto cleanup; + } + retval = close(err_fd[PIPE_READ]); + err_fd[PIPE_READ] = -1; + if (retval == -1) { + ERR(sh, "Unable to close read end of error pipe: %s\n", strerror(errno)); + goto cleanup; + } + + if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status)) { + ERR(sh, "Child process %s did not exit cleanly.", path); + retval = -1; + goto cleanup; + } + if (WEXITSTATUS(status) != 0) { + ERR(sh, "Child process %s failed with code: %d.", path, WEXITSTATUS(status)); + retval = -1; + goto cleanup; + } + } + + retval = 0; + +cleanup: + sigaction(SIGPIPE, &old_signal, NULL); + + if (data_read != NULL) { + *out_data = data_read; + *out_data_len = data_read_len; + } + + if (err_data_read != NULL) { + *err_data = err_data_read; + *err_data_len = err_data_read_len; + } + + if (output_fd[PIPE_READ] != -1) { + close(output_fd[PIPE_READ]); + } + if (output_fd[PIPE_WRITE] != -1) { + close(output_fd[PIPE_WRITE]); + } + if (err_fd[PIPE_READ] != -1) { + close(err_fd[PIPE_READ]); + } + if (err_fd[PIPE_WRITE] != -1) { + close(err_fd[PIPE_WRITE]); + } + if (input_fd[PIPE_READ] != -1) { + close(input_fd[PIPE_READ]); + } + if (input_fd[PIPE_WRITE] != -1) { + close(input_fd[PIPE_WRITE]); + } + + return retval; +} + +static int semanage_direct_write_langext(semanage_handle_t *sh, + char *lang_ext, + const semanage_module_info_t *modinfo) +{ + int ret = -1; + char fn[PATH_MAX]; + FILE *fp = NULL; + + ret = semanage_module_get_path(sh, + modinfo, + SEMANAGE_MODULE_PATH_LANG_EXT, + fn, + sizeof(fn)); + if (ret != 0) { + goto cleanup; + } + + fp = fopen(fn, "w"); + if (fp == NULL) { + ERR(sh, "Unable to open %s module ext file.", modinfo->name); + ret = -1; + goto cleanup; + } + + if (fputs(lang_ext, fp) < 0) { + ERR(sh, "Unable to write %s module ext file.", modinfo->name); + ret = -1; + goto cleanup; + } + + if (fclose(fp) != 0) { + ERR(sh, "Unable to close %s module ext file.", modinfo->name); + ret = -1; + goto cleanup; + } + + fp = NULL; + + ret = 0; + +cleanup: + if (fp != NULL) fclose(fp); + + return ret; +} + +static int semanage_compile_module(semanage_handle_t *sh, + semanage_module_info_t *modinfo) +{ + char cil_path[PATH_MAX]; + char hll_path[PATH_MAX]; + char *compiler_path = NULL; + char *cil_data = NULL; + char *err_data = NULL; + char *hll_data = NULL; + char *start = NULL; + char *end = NULL; + ssize_t hll_data_len = 0; + ssize_t bzip_status; + int status = 0; + int compressed; + size_t cil_data_len; + size_t err_data_len; + + if (!strcasecmp(modinfo->lang_ext, "cil")) { + goto cleanup; + } + + status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path); + if (status != 0) { + goto cleanup; + } + + status = semanage_module_get_path( + sh, + modinfo, + SEMANAGE_MODULE_PATH_CIL, + cil_path, + sizeof(cil_path)); + if (status != 0) { + goto cleanup; + } + + status = semanage_module_get_path( + sh, + modinfo, + SEMANAGE_MODULE_PATH_HLL, + hll_path, + sizeof(hll_path)); + if (status != 0) { + goto cleanup; + } + + if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) { + ERR(sh, "Unable to read file %s\n", hll_path); + status = -1; + goto cleanup; + } + + status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len); + if (err_data_len > 0) { + for (start = end = err_data; end < err_data + err_data_len; end++) { + if (*end == '\n') { + fprintf(stderr, "%s: ", modinfo->name); + fwrite(start, 1, end - start + 1, stderr); + start = end + 1; + } + } + + if (end != start) { + fprintf(stderr, "%s: ", modinfo->name); + fwrite(start, 1, end - start, stderr); + fprintf(stderr, "\n"); + } + } + if (status != 0) { + goto cleanup; + } + + bzip_status = bzip(sh, cil_path, cil_data, cil_data_len); + if (bzip_status == -1) { + ERR(sh, "Failed to bzip %s\n", cil_path); + status = -1; + goto cleanup; + } + + if (sh->conf->remove_hll == 1) { + status = unlink(hll_path); + if (status != 0) { + ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno)); + goto cleanup; + } + + status = semanage_direct_write_langext(sh, "cil", modinfo); + if (status != 0) { + goto cleanup; + } + } + +cleanup: + if (hll_data_len > 0) { + munmap(hll_data, hll_data_len); + } + free(cil_data); + free(err_data); + free(compiler_path); + + return status; +} + +static int semanage_compile_hll_modules(semanage_handle_t *sh, + semanage_module_info_t *modinfos, + int num_modinfos) +{ + int status = 0; + int i; + char cil_path[PATH_MAX]; + + assert(sh); + assert(modinfos); + + for (i = 0; i < num_modinfos; i++) { + status = semanage_module_get_path( + sh, + &modinfos[i], + SEMANAGE_MODULE_PATH_CIL, + cil_path, + sizeof(cil_path)); + if (status != 0) { + goto cleanup; + } + + if (semanage_get_ignore_module_cache(sh) == 0 && + access(cil_path, F_OK) == 0) { + continue; + } + + status = semanage_compile_module(sh, &modinfos[i]); + if (status < 0) { + goto cleanup; + } + } + + status = 0; + +cleanup: + return status; +} + +/********************* direct API functions ********************/ + +/* Commits all changes in sandbox to the actual kernel policy. + * Returns commit number on success, -1 on error. + */ +static int semanage_direct_commit(semanage_handle_t * sh) +{ + char **mod_filenames = NULL; + char *fc_buffer = NULL; + size_t fc_buffer_len = 0; + const char *ofilename = NULL; + const char *path; + int retval = -1, num_modinfos = 0, i, missing_policy_kern = 0, + missing_seusers = 0, missing_fc = 0, missing = 0; + sepol_policydb_t *out = NULL; + struct cil_db *cildb = NULL; + semanage_module_info_t *modinfos = NULL; + + /* Declare some variables */ + int modified = 0, fcontexts_modified, ports_modified, + seusers_modified, users_extra_modified, dontaudit_modified, + preserve_tunables_modified, bools_modified = 0, + disable_dontaudit, preserve_tunables; + dbase_config_t *users = semanage_user_dbase_local(sh); + dbase_config_t *users_base = semanage_user_base_dbase_local(sh); + dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh); + dbase_config_t *users_extra = semanage_user_extra_dbase_local(sh); + dbase_config_t *ports = semanage_port_dbase_local(sh); + dbase_config_t *pports = semanage_port_dbase_policy(sh); + dbase_config_t *bools = semanage_bool_dbase_local(sh); + dbase_config_t *pbools = semanage_bool_dbase_policy(sh); + dbase_config_t *ifaces = semanage_iface_dbase_local(sh); + dbase_config_t *pifaces = semanage_iface_dbase_policy(sh); + dbase_config_t *nodes = semanage_node_dbase_local(sh); + dbase_config_t *pnodes = semanage_node_dbase_policy(sh); + dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh); + dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh); + dbase_config_t *seusers = semanage_seuser_dbase_local(sh); + + /* Create or remove the disable_dontaudit flag file. */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT); + if (access(path, F_OK) == 0) + dontaudit_modified = !(sepol_get_disable_dontaudit(sh->sepolh) == 1); + else + dontaudit_modified = (sepol_get_disable_dontaudit(sh->sepolh) == 1); + if (sepol_get_disable_dontaudit(sh->sepolh) == 1) { + FILE *touch; + touch = fopen(path, "w"); + if (touch != NULL) { + if (fclose(touch) != 0) { + ERR(sh, "Error attempting to create disable_dontaudit flag."); + goto cleanup; + } + } else { + ERR(sh, "Error attempting to create disable_dontaudit flag."); + goto cleanup; + } + } else { + if (remove(path) == -1 && errno != ENOENT) { + ERR(sh, "Error removing the disable_dontaudit flag."); + goto cleanup; + } + } + + /* Create or remove the preserve_tunables flag file. */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES); + if (access(path, F_OK) == 0) + preserve_tunables_modified = !(sepol_get_preserve_tunables(sh->sepolh) == 1); + else + preserve_tunables_modified = (sepol_get_preserve_tunables(sh->sepolh) == 1); + if (sepol_get_preserve_tunables(sh->sepolh) == 1) { + FILE *touch; + touch = fopen(path, "w"); + if (touch != NULL) { + if (fclose(touch) != 0) { + ERR(sh, "Error attempting to create preserve_tunable flag."); + goto cleanup; + } + } else { + ERR(sh, "Error attempting to create preserve_tunable flag."); + goto cleanup; + } + } else { + if (remove(path) == -1 && errno != ENOENT) { + ERR(sh, "Error removing the preserve_tunables flag."); + goto cleanup; + } + } + + /* Before we do anything else, flush the join to its component parts. + * This *does not* flush to disk automatically */ + if (users->dtable->is_modified(users->dbase)) { + retval = users->dtable->flush(sh, users->dbase); + if (retval < 0) + goto cleanup; + } + + /* Decide if anything was modified */ + fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase); + seusers_modified = seusers->dtable->is_modified(seusers->dbase); + users_extra_modified = + users_extra->dtable->is_modified(users_extra->dbase); + ports_modified = ports->dtable->is_modified(ports->dbase); + bools_modified = bools->dtable->is_modified(bools->dbase); + + modified = sh->modules_modified; + modified |= seusers_modified; + modified |= users_extra_modified; + modified |= ports_modified; + modified |= users->dtable->is_modified(users_base->dbase); + modified |= ifaces->dtable->is_modified(ifaces->dbase); + modified |= nodes->dtable->is_modified(nodes->dbase); + modified |= dontaudit_modified; + modified |= preserve_tunables_modified; + + /* This is for systems that have already migrated with an older version + * of semanage_migrate_store. The older version did not copy policy.kern so + * the policy binary must be rebuilt here. + */ + if (!sh->do_rebuild && !modified) { + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL); + + if (access(path, F_OK) != 0) { + missing_policy_kern = 1; + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); + + if (access(path, F_OK) != 0) { + missing_fc = 1; + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); + + if (access(path, F_OK) != 0) { + missing_seusers = 1; + } + } + + missing |= missing_policy_kern; + missing |= missing_fc; + missing |= missing_seusers; + + /* If there were policy changes, or explicitly requested, rebuild the policy */ + if (sh->do_rebuild || modified || missing) { + /* =================== Module expansion =============== */ + + retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos); + if (retval < 0) { + goto cleanup; + } + + if (num_modinfos == 0) { + goto cleanup; + } + + retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos); + if (retval < 0) { + ERR(sh, "Failed to compile hll files into cil files.\n"); + goto cleanup; + } + + retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames); + if (retval < 0) + goto cleanup; + + retval = semanage_verify_modules(sh, mod_filenames, num_modinfos); + if (retval < 0) + goto cleanup; + + cil_db_init(&cildb); + + disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh); + preserve_tunables = sepol_get_preserve_tunables(sh->sepolh); + cil_set_disable_dontaudit(cildb, disable_dontaudit); + cil_set_disable_neverallow(cildb, !(sh->conf->expand_check)); + cil_set_preserve_tunables(cildb, preserve_tunables); + cil_set_target_platform(cildb, sh->conf->target_platform); + cil_set_policy_version(cildb, sh->conf->policyvers); + + if (sh->conf->handle_unknown != -1) { + cil_set_handle_unknown(cildb, sh->conf->handle_unknown); + } + + retval = semanage_load_files(sh, cildb, mod_filenames, num_modinfos); + if (retval < 0) { + goto cleanup; + } + + retval = cil_compile(cildb); + if (retval < 0) + goto cleanup; + + retval = cil_build_policydb(cildb, &out); + if (retval < 0) + goto cleanup; + + /* File Contexts */ + retval = cil_filecons_to_string(cildb, &fc_buffer, &fc_buffer_len); + if (retval < 0) + goto cleanup; + + /* Write the contexts (including template contexts) to a single file. */ + ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL); + if (ofilename == NULL) { + retval = -1; + goto cleanup; + } + retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len); + if (retval < 0) + goto cleanup; + + /* Split complete and template file contexts into their separate files. */ + retval = semanage_split_fc(sh); + if (retval < 0) + goto cleanup; + + /* remove FC_TMPL now that it is now longer needed */ + unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL)); + + pfcontexts->dtable->drop_cache(pfcontexts->dbase); + + /* SEUsers */ + retval = semanage_direct_update_seuser(sh, cildb); + if (retval < 0) + goto cleanup; + + /* User Extra */ + retval = semanage_direct_update_user_extra(sh, cildb); + if (retval < 0) + goto cleanup; + + cil_db_destroy(&cildb); + + } else { + /* Load already linked policy */ + retval = sepol_policydb_create(&out); + if (retval < 0) + goto cleanup; + + retval = semanage_read_policydb(sh, out); + if (retval < 0) + goto cleanup; + } + + if (sh->do_rebuild || modified || bools_modified) { + /* Attach to policy databases that work with a policydb. */ + dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out); + dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out); + dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out); + dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out); + dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out); + + /* ============= Apply changes, and verify =============== */ + + retval = semanage_base_merge_components(sh); + if (retval < 0) + goto cleanup; + + retval = semanage_write_policydb(sh, out); + if (retval < 0) + goto cleanup; + + retval = semanage_verify_kernel(sh); + if (retval < 0) + goto cleanup; + } else { + retval = semanage_base_merge_components(sh); + if (retval < 0) + goto cleanup; + } + + /* ======= Post-process: Validate non-policydb components ===== */ + + /* Validate local modifications to file contexts. + * Note: those are still cached, even though they've been + * merged into the main file_contexts. We won't check the + * large file_contexts - checked at compile time */ + if (sh->do_rebuild || modified || fcontexts_modified) { + retval = semanage_fcontext_validate_local(sh, out); + if (retval < 0) + goto cleanup; + } + + /* Validate local seusers against policy */ + if (sh->do_rebuild || modified || seusers_modified) { + retval = semanage_seuser_validate_local(sh, out); + if (retval < 0) + goto cleanup; + } + + /* Validate local ports for overlap */ + if (sh->do_rebuild || modified || ports_modified) { + retval = semanage_port_validate_local(sh); + if (retval < 0) + goto cleanup; + } + + /* ================== Write non-policydb components ========= */ + + /* Commit changes to components */ + retval = semanage_commit_components(sh); + if (retval < 0) + goto cleanup; + + retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL), + sh->conf->file_mode); + if (retval < 0) { + goto cleanup; + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL); + if (access(path, F_OK) == 0) { + retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL), + sh->conf->file_mode); + if (retval < 0) { + goto cleanup; + } + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); + if (access(path, F_OK) == 0) { + retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC), + sh->conf->file_mode); + if (retval < 0) { + goto cleanup; + } + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); + if (access(path, F_OK) == 0) { + retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS), + sh->conf->file_mode); + if (retval < 0) { + goto cleanup; + } + } + + /* run genhomedircon if its enabled, this should be the last operation + * which requires the out policydb */ + if (!sh->conf->disable_genhomedircon) { + if (out && (retval = + semanage_genhomedircon(sh, out, sh->conf->usepasswd, sh->conf->ignoredirs)) != 0) { + ERR(sh, "semanage_genhomedircon returned error code %d.", + retval); + goto cleanup; + } + } else { + WARN(sh, "WARNING: genhomedircon is disabled. \ + See /etc/selinux/semanage.conf if you need to enable it."); + } + + /* free out, if we don't free it before calling semanage_install_sandbox + * then fork() may fail on low memory machines */ + sepol_policydb_free(out); + out = NULL; + + if (sh->do_rebuild || modified || bools_modified || fcontexts_modified) { + retval = semanage_install_sandbox(sh); + } + +cleanup: + for (i = 0; i < num_modinfos; i++) { + semanage_module_info_destroy(sh, &modinfos[i]); + } + free(modinfos); + + for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) { + free(mod_filenames[i]); + } + + if (modified || bools_modified) { + /* Detach from policydb, so it can be freed */ + dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase); + dbase_policydb_detach((dbase_policydb_t *) pports->dbase); + dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase); + dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase); + dbase_policydb_detach((dbase_policydb_t *) pbools->dbase); + } + + free(mod_filenames); + sepol_policydb_free(out); + cil_db_destroy(&cildb); + semanage_release_trans_lock(sh); + + free(fc_buffer); + + /* regardless if the commit was successful or not, remove the + sandbox if it is still there */ + semanage_remove_directory(semanage_path + (SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); + semanage_remove_directory(semanage_final_path + (SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)); + return retval; +} + +/* Writes a module to the sandbox's module directory, overwriting any + * previous module stored within. Note that module data are not + * free()d by this function; caller is responsible for deallocating it + * if necessary. Returns 0 on success, -1 if out of memory, -2 if the + * data does not represent a valid module file, -3 if error while + * writing file. */ +static int semanage_direct_install(semanage_handle_t * sh, + char *data, size_t data_len, + const char *module_name, const char *lang_ext) +{ + int status = 0; + int ret = 0; + + semanage_module_info_t modinfo; + ret = semanage_module_info_init(sh, &modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_name(sh, &modinfo, module_name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_enabled(sh, &modinfo, -1); + if (ret != 0) { + status = -1; + goto cleanup; + } + + status = semanage_direct_install_info(sh, &modinfo, data, data_len); + +cleanup: + + semanage_module_info_destroy(sh, &modinfo); + + return status; +} + +/* Attempts to link a module to the sandbox's module directory, unlinking any + * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the + * data does not represent a valid module file, -3 if error while + * writing file. */ + +static int semanage_direct_install_file(semanage_handle_t * sh, + const char *install_filename) +{ + + int retval = -1; + char *data = NULL; + ssize_t data_len = 0; + int compressed = 0; + char *path = NULL; + char *filename; + char *lang_ext = NULL; + char *separator; + + if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) { + ERR(sh, "Unable to read file %s\n", install_filename); + retval = -1; + goto cleanup; + } + + path = strdup(install_filename); + if (path == NULL) { + ERR(sh, "No memory available for strdup.\n"); + retval = -1; + goto cleanup; + } + + filename = basename(path); + + if (compressed) { + separator = strrchr(filename, '.'); + if (separator == NULL) { + ERR(sh, "Compressed module does not have a valid extension."); + retval = -1; + goto cleanup; + } + *separator = '\0'; + lang_ext = separator + 1; + } + + separator = strrchr(filename, '.'); + if (separator == NULL) { + if (lang_ext == NULL) { + ERR(sh, "Module does not have a valid extension."); + retval = -1; + goto cleanup; + } + } else { + *separator = '\0'; + lang_ext = separator + 1; + } + + retval = semanage_direct_install(sh, data, data_len, filename, lang_ext); + +cleanup: + if (data_len > 0) munmap(data, data_len); + free(path); + + return retval; +} + +static int semanage_direct_extract(semanage_handle_t * sh, + semanage_module_key_t *modkey, + int extract_cil, + void **mapped_data, + size_t *data_len, + semanage_module_info_t **modinfo) +{ + char module_path[PATH_MAX]; + char input_file[PATH_MAX]; + enum semanage_module_path_type file_type; + int rc = -1; + semanage_module_info_t *_modinfo = NULL; + ssize_t _data_len; + char *_data; + int compressed; + + /* get path of module */ + rc = semanage_module_get_path( + sh, + (const semanage_module_info_t *)modkey, + SEMANAGE_MODULE_PATH_NAME, + module_path, + sizeof(module_path)); + if (rc != 0) { + goto cleanup; + } + + if (access(module_path, F_OK) != 0) { + ERR(sh, "Module does not exist: %s", module_path); + rc = -1; + goto cleanup; + } + + rc = semanage_module_get_module_info(sh, + modkey, + &_modinfo); + if (rc != 0) { + goto cleanup; + } + + if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) { + file_type = SEMANAGE_MODULE_PATH_CIL; + } else { + file_type = SEMANAGE_MODULE_PATH_HLL; + } + + /* get path of what to extract */ + rc = semanage_module_get_path( + sh, + _modinfo, + file_type, + input_file, + sizeof(input_file)); + if (rc != 0) { + goto cleanup; + } + + if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && access(input_file, F_OK) != 0) { + rc = semanage_compile_module(sh, _modinfo); + if (rc < 0) { + goto cleanup; + } + } + + _data_len = map_file(sh, input_file, &_data, &compressed); + if (_data_len <= 0) { + ERR(sh, "Error mapping file: %s", input_file); + rc = -1; + goto cleanup; + } + + *modinfo = _modinfo; + *data_len = (size_t)_data_len; + *mapped_data = _data; + +cleanup: + if (rc != 0) { + semanage_module_info_destroy(sh, _modinfo); + free(_modinfo); + } + + return rc; +} + +/* Removes a module from the sandbox. Returns 0 on success, -1 if out + * of memory, -2 if module not found or could not be removed. */ +static int semanage_direct_remove(semanage_handle_t * sh, char *module_name) +{ + int status = 0; + int ret = 0; + + semanage_module_key_t modkey; + ret = semanage_module_key_init(sh, &modkey); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_key_set_priority(sh, &modkey, sh->priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_key_set_name(sh, &modkey, module_name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + status = semanage_direct_remove_key(sh, &modkey); + +cleanup: + return status; +} + +/* Allocate an array of module_info structures for each readable + * module within the store. Note that if the calling program has + * already begun a transaction then this function will get a list of + * modules within the sandbox. The caller is responsible for calling + * semanage_module_info_datum_destroy() on each element of the array + * as well as free()ing the entire list. + */ +static int semanage_direct_list(semanage_handle_t * sh, + semanage_module_info_t ** modinfo, + int *num_modules) +{ + int i, retval = -1; + *modinfo = NULL; + *num_modules = 0; + + /* get the read lock when reading from the active + (non-transaction) directory */ + if (!sh->is_in_transaction) + if (semanage_get_active_lock(sh) < 0) + return -1; + + if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) { + goto cleanup; + } + + if (num_modules == 0) { + retval = semanage_direct_get_serial(sh); + goto cleanup; + } + + retval = semanage_direct_get_serial(sh); + + cleanup: + if (retval < 0) { + for (i = 0; i < *num_modules; i++) { + semanage_module_info_destroy(sh, &(*modinfo[i])); + modinfo[i] = NULL; + } + free(*modinfo); + *modinfo = NULL; + } + + if (!sh->is_in_transaction) { + semanage_release_active_lock(sh); + } + return retval; +} + +static int semanage_direct_get_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int *enabled) +{ + assert(sh); + assert(modkey); + assert(enabled); + + int status = 0; + int ret = 0; + + char path[PATH_MAX]; + struct stat sb; + semanage_module_info_t *modinfo = NULL; + + /* get module info */ + ret = semanage_module_get_module_info( + sh, + modkey, + &modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get disabled file path */ + ret = semanage_module_get_path( + sh, + modinfo, + SEMANAGE_MODULE_PATH_DISABLED, + path, + sizeof(path)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + if (stat(path, &sb) < 0) { + *enabled = 1; + } + else { + *enabled = 0; + } + +cleanup: + semanage_module_info_destroy(sh, modinfo); + free(modinfo); + + return status; +} + +static int semanage_direct_set_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int enabled) +{ + assert(sh); + assert(modkey); + + int status = 0; + int ret = 0; + + char fn[PATH_MAX]; + const char *path = NULL; + FILE *fp = NULL; + semanage_module_info_t *modinfo = NULL; + + /* check transaction */ + if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + status = -1; + goto cleanup; + } + } + + /* validate name */ + ret = semanage_module_validate_name(modkey->name); + if (ret != 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modkey->name); + status = -1; + goto cleanup; + } + + /* validate enabled */ + ret = semanage_module_validate_enabled(enabled); + if (ret != 0) { + errno = 0; + ERR(sh, "Enabled status %d is invalid.", enabled); + status = -1; + goto cleanup; + } + + /* check for disabled path, create if missing */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); + + ret = semanage_mkdir(sh, path); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get module info */ + ret = semanage_module_get_module_info( + sh, + modkey, + &modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get module disabled file */ + ret = semanage_module_get_path( + sh, + modinfo, + SEMANAGE_MODULE_PATH_DISABLED, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + switch (enabled) { + case 0: /* disable the module */ + fp = fopen(fn, "w"); + + if (fp == NULL) { + ERR(sh, + "Unable to disable module %s", + modkey->name); + status = -1; + goto cleanup; + } + + if (fclose(fp) != 0) { + ERR(sh, + "Unable to close disabled file for module %s", + modkey->name); + status = -1; + goto cleanup; + } + + fp = NULL; + + break; + case 1: /* enable the module */ + if (unlink(fn) < 0) { + if (errno != ENOENT) { + ERR(sh, + "Unable to enable module %s", + modkey->name); + status = -1; + goto cleanup; + } + else { + /* module already enabled */ + errno = 0; + } + } + + break; + case -1: /* warn about ignored setting to default */ + WARN(sh, + "Setting module %s to 'default' state has no effect", + modkey->name); + break; + } + +cleanup: + semanage_module_info_destroy(sh, modinfo); + free(modinfo); + + if (fp != NULL) fclose(fp); + return status; +} + +int semanage_direct_access_check(semanage_handle_t * sh) +{ + if (semanage_check_init(sh, sh->conf->store_root_path)) + return -1; + + return semanage_store_access_check(); +} + +int semanage_direct_mls_enabled(semanage_handle_t * sh) +{ + sepol_policydb_t *p = NULL; + int retval; + + retval = sepol_policydb_create(&p); + if (retval < 0) + goto cleanup; + + retval = semanage_read_policydb(sh, p); + if (retval < 0) + goto cleanup; + + retval = sepol_policydb_mls_enabled(p); +cleanup: + sepol_policydb_free(p); + return retval; +} + +static int semanage_direct_get_module_info(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + semanage_module_info_t **modinfo) +{ + assert(sh); + assert(modkey); + assert(modinfo); + + int status = 0; + int ret = 0; + + char fn[PATH_MAX]; + FILE *fp = NULL; + size_t size = 0; + struct stat sb; + char *tmp = NULL; + + int i = 0; + + semanage_module_info_t *modinfos = NULL; + int modinfos_len = 0; + semanage_module_info_t *highest = NULL; + + /* check module name */ + ret = semanage_module_validate_name(modkey->name); + if (ret < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modkey->name); + status = -1; + goto cleanup; + } + + /* if priority == 0, then find the highest priority available */ + if (modkey->priority == 0) { + ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len); + if (ret != 0) { + status = -1; + goto cleanup; + } + + for (i = 0; i < modinfos_len; i++) { + ret = strcmp(modinfos[i].name, modkey->name); + if (ret == 0) { + highest = &modinfos[i]; + break; + } + } + + if (highest == NULL) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_create(sh, modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_clone(sh, highest, *modinfo); + if (ret != 0) { + status = -1; + } + + /* skip to cleanup, module was found */ + goto cleanup; + } + + /* check module priority */ + ret = semanage_module_validate_priority(modkey->priority); + if (ret != 0) { + errno = 0; + ERR(sh, "Priority %d is invalid.", modkey->priority); + status = -1; + goto cleanup; + } + + /* copy in key values */ + ret = semanage_module_info_create(sh, modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_name(sh, *modinfo, modkey->name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* lookup module ext */ + ret = semanage_module_get_path(sh, + *modinfo, + SEMANAGE_MODULE_PATH_LANG_EXT, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + fp = fopen(fn, "r"); + + if (fp == NULL) { + ERR(sh, + "Unable to open %s module lang ext file at %s.", + (*modinfo)->name, fn); + status = -1; + goto cleanup; + } + + /* set module ext */ + if (getline(&tmp, &size, fp) < 0) { + ERR(sh, + "Unable to read %s module lang ext file.", + (*modinfo)->name); + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp); + if (ret != 0) { + status = -1; + goto cleanup; + } + free(tmp); + tmp = NULL; + + if (fclose(fp) != 0) { + ERR(sh, + "Unable to close %s module lang ext file.", + (*modinfo)->name); + status = -1; + goto cleanup; + } + + fp = NULL; + + /* lookup enabled/disabled status */ + ret = semanage_module_get_path(sh, + *modinfo, + SEMANAGE_MODULE_PATH_DISABLED, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* set enabled/disabled status */ + if (stat(fn, &sb) < 0) { + ret = semanage_module_info_set_enabled(sh, *modinfo, 1); + if (ret != 0) { + status = -1; + goto cleanup; + } + } + else { + ret = semanage_module_info_set_enabled(sh, *modinfo, 0); + if (ret != 0) { + status = -1; + goto cleanup; + } + } + +cleanup: + free(tmp); + + if (modinfos != NULL) { + for (i = 0; i < modinfos_len; i++) { + semanage_module_info_destroy(sh, &modinfos[i]); + } + free(modinfos); + } + + if (fp != NULL) fclose(fp); + return status; +} + +static int semanage_direct_set_module_info(semanage_handle_t *sh, + const semanage_module_info_t *modinfo) +{ + int status = 0; + int ret = 0; + + char fn[PATH_MAX]; + const char *path = NULL; + int enabled = 0; + semanage_module_info_t *modinfo_tmp = NULL; + + semanage_module_key_t modkey; + ret = semanage_module_key_init(sh, &modkey); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* check transaction */ + if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + status = -1; + goto cleanup; + } + } + + /* validate module */ + ret = semanage_module_info_validate(modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + sh->modules_modified = 1; + + /* check for modules path, create if missing */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); + + ret = semanage_mkdir(sh, path); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* write priority */ + ret = semanage_module_get_path(sh, + modinfo, + SEMANAGE_MODULE_PATH_PRIORITY, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_mkdir(sh, fn); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* write name */ + ret = semanage_module_get_path(sh, + modinfo, + SEMANAGE_MODULE_PATH_NAME, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_mkdir(sh, fn); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* write ext */ + ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* write enabled/disabled status */ + + /* check for disabled path, create if missing */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); + + ret = semanage_mkdir(sh, path); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_get_path(sh, + modinfo, + SEMANAGE_MODULE_PATH_DISABLED, + fn, + sizeof(fn)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_key_set_name(sh, &modkey, modinfo->name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + if (modinfo->enabled == -1) { + /* default to enabled */ + enabled = 1; + + /* check if a module is already installed */ + ret = semanage_module_get_module_info(sh, + &modkey, + &modinfo_tmp); + if (ret == 0) { + /* set enabled status to current one */ + enabled = modinfo_tmp->enabled; + } + } + else { + enabled = modinfo->enabled; + } + + ret = semanage_module_set_enabled(sh, &modkey, enabled); + if (ret != 0) { + status = -1; + goto cleanup; + } + +cleanup: + semanage_module_key_destroy(sh, &modkey); + + semanage_module_info_destroy(sh, modinfo_tmp); + free(modinfo_tmp); + + return status; +} + +static int semanage_priorities_filename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.' || + strcmp(d->d_name, "disabled") == 0) + return 0; + return 1; +} + +static int semanage_modules_filename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.') + return 0; + return 1; +} + +static int semanage_direct_list_all(semanage_handle_t *sh, + semanage_module_info_t **modinfos, + int *modinfos_len) +{ + assert(sh); + assert(modinfos); + assert(modinfos_len); + + int status = 0; + int ret = 0; + + int i = 0; + int j = 0; + + *modinfos = NULL; + *modinfos_len = 0; + void *tmp = NULL; + + const char *toplevel = NULL; + + struct dirent **priorities = NULL; + int priorities_len = 0; + char priority_path[PATH_MAX]; + + struct dirent **modules = NULL; + int modules_len = 0; + + uint16_t priority = 0; + + semanage_module_info_t *modinfo_tmp = NULL; + + semanage_module_info_t modinfo; + ret = semanage_module_info_init(sh, &modinfo); + if (ret != 0) { + status = -1; + goto cleanup; + } + + if (sh->is_in_transaction) { + toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); + } else { + toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); + } + + /* find priorities */ + priorities_len = scandir(toplevel, + &priorities, + semanage_priorities_filename_select, + versionsort); + if (priorities_len == -1) { + ERR(sh, "Error while scanning directory %s.", toplevel); + status = -1; + goto cleanup; + } + + /* for each priority directory */ + /* loop through in reverse so that highest priority is first */ + for (i = priorities_len - 1; i >= 0; i--) { + /* convert priority string to uint16_t */ + ret = semanage_string_to_priority(priorities[i]->d_name, + &priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* set our priority */ + ret = semanage_module_info_set_priority(sh, + &modinfo, + priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get the priority path */ + ret = semanage_module_get_path(sh, + &modinfo, + SEMANAGE_MODULE_PATH_PRIORITY, + priority_path, + sizeof(priority_path)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* cleanup old modules */ + if (modules != NULL) { + for (j = 0; j < modules_len; j++) { + free(modules[j]); + modules[j] = NULL; + } + free(modules); + modules = NULL; + modules_len = 0; + } + + /* find modules at this priority */ + modules_len = scandir(priority_path, + &modules, + semanage_modules_filename_select, + versionsort); + if (modules_len == -1) { + ERR(sh, + "Error while scanning directory %s.", + priority_path); + status = -1; + goto cleanup; + } + + if (modules_len == 0) continue; + + /* add space for modules */ + tmp = realloc(*modinfos, + sizeof(semanage_module_info_t) * + (*modinfos_len + modules_len)); + if (tmp == NULL) { + ERR(sh, "Error allocating memory for module array."); + status = -1; + goto cleanup; + } + *modinfos = tmp; + + /* for each module directory */ + for(j = 0; j < modules_len; j++) { + /* set module name */ + ret = semanage_module_info_set_name( + sh, + &modinfo, + modules[j]->d_name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get module values */ + ret = semanage_direct_get_module_info( + sh, + (const semanage_module_key_t *) + (&modinfo), + &modinfo_tmp); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* copy into array */ + ret = semanage_module_info_init( + sh, + &((*modinfos)[*modinfos_len])); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_clone( + sh, + modinfo_tmp, + &((*modinfos)[*modinfos_len])); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_destroy(sh, modinfo_tmp); + if (ret != 0) { + status = -1; + goto cleanup; + } + free(modinfo_tmp); + modinfo_tmp = NULL; + + *modinfos_len += 1; + } + } + +cleanup: + semanage_module_info_destroy(sh, &modinfo); + + if (priorities != NULL) { + for (i = 0; i < priorities_len; i++) { + free(priorities[i]); + } + free(priorities); + } + + if (modules != NULL) { + for (i = 0; i < modules_len; i++) { + free(modules[i]); + } + free(modules); + } + + ret = semanage_module_info_destroy(sh, modinfo_tmp); + if (ret != 0) { + status = -1; + goto cleanup; + } + free(modinfo_tmp); + modinfo_tmp = NULL; + + if (status != 0) { + if (modinfos != NULL) { + for (i = 0; i < *modinfos_len; i++) { + semanage_module_info_destroy( + sh, + &(*modinfos)[i]); + } + free(*modinfos); + *modinfos = NULL; + *modinfos_len = 0; + } + } + + return status; +} + +static int semanage_direct_install_info(semanage_handle_t *sh, + const semanage_module_info_t *modinfo, + char *data, + size_t data_len) +{ + assert(sh); + assert(modinfo); + assert(data); + + int status = 0; + int ret = 0; + int type; + + char path[PATH_MAX]; + + semanage_module_info_t *higher_info = NULL; + semanage_module_key_t higher_key; + ret = semanage_module_key_init(sh, &higher_key); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* validate module info */ + ret = semanage_module_info_validate(modinfo); + if (ret != 0) { + ERR(sh, "%s failed module validation.\n", modinfo->name); + status = -2; + goto cleanup; + } + + /* Check for higher priority module and warn if there is one as + * it will override the module currently being installed. + */ + ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info); + if (ret == 0) { + if (higher_info->priority > modinfo->priority) { + errno = 0; + WARN(sh, + "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.", + modinfo->name, + higher_info->priority, + modinfo->priority); + } + else if (higher_info->priority < modinfo->priority) { + errno = 0; + INFO(sh, + "Overriding %s module at lower priority %d with module at priority %d.", + modinfo->name, + higher_info->priority, + modinfo->priority); + } + + if (higher_info->enabled == 0 && modinfo->enabled == -1) { + errno = 0; + WARN(sh, + "%s module will be disabled after install due to default enabled status.", + modinfo->name); + } + } + + /* set module meta data */ + ret = semanage_direct_set_module_info(sh, modinfo); + if (ret != 0) { + status = -2; + goto cleanup; + } + + /* install module source file */ + if (!strcasecmp(modinfo->lang_ext, "cil")) { + type = SEMANAGE_MODULE_PATH_CIL; + } else { + type = SEMANAGE_MODULE_PATH_HLL; + } + ret = semanage_module_get_path( + sh, + modinfo, + type, + path, + sizeof(path)); + if (ret != 0) { + status = -3; + goto cleanup; + } + + ret = bzip(sh, path, data, data_len); + if (ret <= 0) { + ERR(sh, "Error while writing to %s.", path); + status = -3; + goto cleanup; + } + + /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */ + if (type == SEMANAGE_MODULE_PATH_HLL) { + ret = semanage_module_get_path( + sh, + modinfo, + SEMANAGE_MODULE_PATH_CIL, + path, + sizeof(path)); + if (ret != 0) { + status = -3; + goto cleanup; + } + + if (access(path, F_OK) == 0) { + ret = unlink(path); + if (ret != 0) { + ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno)); + status = -3; + goto cleanup; + } + } + } + +cleanup: + semanage_module_key_destroy(sh, &higher_key); + semanage_module_info_destroy(sh, higher_info); + free(higher_info); + + return status; +} + +static int semanage_direct_remove_key(semanage_handle_t *sh, + const semanage_module_key_t *modkey) +{ + assert(sh); + assert(modkey); + + int status = 0; + int ret = 0; + + char path[PATH_MAX]; + semanage_module_info_t *modinfo = NULL; + + semanage_module_key_t modkey_tmp; + ret = semanage_module_key_init(sh, &modkey_tmp); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* validate module key */ + ret = semanage_module_validate_priority(modkey->priority); + if (ret != 0) { + errno = 0; + ERR(sh, "Priority %d is invalid.", modkey->priority); + status = -1; + goto cleanup; + } + + ret = semanage_module_validate_name(modkey->name); + if (ret != 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modkey->name); + status = -1; + goto cleanup; + } + + ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + /* get module path */ + ret = semanage_module_get_path( + sh, + (const semanage_module_info_t *)modkey, + SEMANAGE_MODULE_PATH_NAME, + path, + sizeof(path)); + if (ret != 0) { + status = -2; + goto cleanup; + } + + /* remove directory */ + ret = semanage_remove_directory(path); + if (ret != 0) { + ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority); + status = -2; + goto cleanup; + } + + /* check if its the last module at any priority */ + ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo); + if (ret != 0) { + /* info that no other module will override */ + errno = 0; + INFO(sh, + "Removing last %s module (no other %s module exists at another priority).", + modkey->name, + modkey->name); + + /* remove disabled status file */ + ret = semanage_module_get_path( + sh, + (const semanage_module_info_t *)modkey, + SEMANAGE_MODULE_PATH_DISABLED, + path, + sizeof(path)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + struct stat sb; + if (stat(path, &sb) == 0) { + ret = unlink(path); + if (ret != 0) { + status = -1; + goto cleanup; + } + } + } + else { + /* if a lower priority module is going to become active */ + if (modkey->priority > modinfo->priority) { + /* inform what the new active module will be */ + errno = 0; + INFO(sh, + "%s module at priority %d is now active.", + modinfo->name, + modinfo->priority); + } + } + +cleanup: + semanage_module_key_destroy(sh, &modkey_tmp); + + semanage_module_info_destroy(sh, modinfo); + free(modinfo); + + return status; +} +
diff --git a/selinux/libsemanage/src/direct_api.h b/selinux/libsemanage/src/direct_api.h new file mode 100644 index 0000000..e56107b --- /dev/null +++ b/selinux/libsemanage/src/direct_api.h
@@ -0,0 +1,46 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_DIRECT_API_H_ +#define _SEMANAGE_DIRECT_API_H_ + +/* Circular dependency */ +struct semanage_handle; + +/* Direct component of handle */ +struct semanage_direct_handle { + + /* Locking */ + int activelock_file_fd; + int translock_file_fd; +}; + +int semanage_direct_connect(struct semanage_handle *sh); + +int semanage_direct_is_managed(struct semanage_handle *sh); + +int semanage_direct_access_check(struct semanage_handle *sh); + +int semanage_direct_mls_enabled(struct semanage_handle *sh); + +#include <stdio.h> +#include <unistd.h> +ssize_t bunzip(struct semanage_handle *sh, FILE *f, char **data); + +#endif
diff --git a/selinux/libsemanage/src/dso.h b/selinux/libsemanage/src/dso.h new file mode 100644 index 0000000..5c69aae --- /dev/null +++ b/selinux/libsemanage/src/dso.h
@@ -0,0 +1,23 @@ +#ifndef _SEPOL_DSO_H +#define _SEPOL_DSO_H 1 + +#ifdef SHARED +# define hidden __attribute__ ((visibility ("hidden"))) +# define hidden_proto(fct) __hidden_proto (fct, fct##_internal) +# define __hidden_proto(fct, internal) \ + extern __typeof (fct) internal; \ + extern __typeof (fct) fct __asm (#internal) hidden; +# if defined(__alpha__) || defined(__mips__) +# define hidden_def(fct) \ + asm (".globl " #fct "\n" #fct " = " #fct "_internal"); +# else +# define hidden_def(fct) \ + asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); +#endif +#else +# define hidden +# define hidden_proto(fct) +# define hidden_def(fct) +#endif + +#endif
diff --git a/selinux/libsemanage/src/exception.sh b/selinux/libsemanage/src/exception.sh new file mode 100644 index 0000000..d18959c --- /dev/null +++ b/selinux/libsemanage/src/exception.sh
@@ -0,0 +1,14 @@ +function except() { +echo " +%exception $1 { + \$action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } +} +" +} +${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h +for i in `awk '/extern int/ { print $6 }' temp.aux`; do except $i ; done +rm -f -- temp.aux -.o
diff --git a/selinux/libsemanage/src/fcontext_internal.h b/selinux/libsemanage/src/fcontext_internal.h new file mode 100644 index 0000000..a6008ea --- /dev/null +++ b/selinux/libsemanage/src/fcontext_internal.h
@@ -0,0 +1,43 @@ +#ifndef _SEMANAGE_FCONTEXT_INTERNAL_H_ +#define _SEMANAGE_FCONTEXT_INTERNAL_H_ + +#include <semanage/fcontext_record.h> +#include <semanage/fcontexts_local.h> +#include <semanage/fcontexts_policy.h> +#include <sepol/policydb.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_fcontext_key_create) + hidden_proto(semanage_fcontext_key_extract) + hidden_proto(semanage_fcontext_key_free) + hidden_proto(semanage_fcontext_compare) + hidden_proto(semanage_fcontext_compare2) + hidden_proto(semanage_fcontext_create) + hidden_proto(semanage_fcontext_get_expr) + hidden_proto(semanage_fcontext_set_expr) + hidden_proto(semanage_fcontext_get_type) + hidden_proto(semanage_fcontext_get_type_str) + hidden_proto(semanage_fcontext_set_type) + hidden_proto(semanage_fcontext_get_con) + hidden_proto(semanage_fcontext_set_con) + hidden_proto(semanage_fcontext_clone) + hidden_proto(semanage_fcontext_free) + hidden_proto(semanage_fcontext_iterate_local) + +/* FCONTEXT RECORD: metod table */ +extern record_table_t SEMANAGE_FCONTEXT_RTABLE; + +extern int fcontext_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void fcontext_file_dbase_release(dbase_config_t * dconfig); + +extern int hidden semanage_fcontext_validate_local(semanage_handle_t * handle, + const sepol_policydb_t * + policydb); + +#endif
diff --git a/selinux/libsemanage/src/fcontext_record.c b/selinux/libsemanage/src/fcontext_record.c new file mode 100644 index 0000000..f39efa1 --- /dev/null +++ b/selinux/libsemanage/src/fcontext_record.c
@@ -0,0 +1,317 @@ +struct semanage_fcontext; +struct semanage_fcontext_key; +typedef struct semanage_fcontext record_t; +typedef struct semanage_fcontext_key record_key_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include <string.h> +#include "fcontext_internal.h" +#include "context_internal.h" +#include "debug.h" + +struct semanage_fcontext { + + /* Matching expression */ + char *expr; + + /* Type of object */ + int type; + + /* Context */ + semanage_context_t *con; +}; + +struct semanage_fcontext_key { + + /* Matching expression */ + char *expr; + + /* Type of object */ + int type; +}; + +/* Key */ +int semanage_fcontext_key_create(semanage_handle_t * handle, + const char *expr, + int type, semanage_fcontext_key_t ** key_ptr) +{ + + semanage_fcontext_key_t *tmp_key = + (semanage_fcontext_key_t *) malloc(sizeof(semanage_fcontext_key_t)); + + if (!tmp_key) { + ERR(handle, "out of memory, could not " + "create file context key"); + return STATUS_ERR; + } + tmp_key->expr = strdup(expr); + if (!tmp_key->expr) { + ERR(handle, "out of memory, could not create file context key."); + free(tmp_key); + return STATUS_ERR; + } + tmp_key->type = type; + + *key_ptr = tmp_key; + return STATUS_SUCCESS; +} + +hidden_def(semanage_fcontext_key_create) + +int semanage_fcontext_key_extract(semanage_handle_t * handle, + const semanage_fcontext_t * fcontext, + semanage_fcontext_key_t ** key_ptr) +{ + + if (semanage_fcontext_key_create(handle, fcontext->expr, + fcontext->type, key_ptr) < 0) { + ERR(handle, "could not extract key from " + "file context %s (%s)", fcontext->expr, + semanage_fcontext_get_type_str(fcontext->type)); + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +hidden_def(semanage_fcontext_key_extract) + +void semanage_fcontext_key_free(semanage_fcontext_key_t * key) +{ + free(key->expr); + free(key); +} + +hidden_def(semanage_fcontext_key_free) + +int semanage_fcontext_compare(const semanage_fcontext_t * fcontext, + const semanage_fcontext_key_t * key) +{ + + int rv = strcmp(fcontext->expr, key->expr); + if (rv != 0) + return rv; + else { + if (fcontext->type < key->type) + return -1; + + else if (key->type < fcontext->type) + return 1; + + else + return 0; + } +} + +hidden_def(semanage_fcontext_compare) + +int semanage_fcontext_compare2(const semanage_fcontext_t * fcontext, + const semanage_fcontext_t * fcontext2) +{ + + int rv = strcmp(fcontext->expr, fcontext2->expr); + if (rv != 0) + return rv; + else { + if (fcontext->type < fcontext2->type) + return -1; + + else if (fcontext2->type < fcontext->type) + return 1; + + else + return 0; + } +} + +hidden_def(semanage_fcontext_compare2) + +static int semanage_fcontext_compare2_qsort(const semanage_fcontext_t ** + fcontext, + const semanage_fcontext_t ** + fcontext2) +{ + + return semanage_fcontext_compare2(*fcontext, *fcontext2); +} + +/* Create */ +int semanage_fcontext_create(semanage_handle_t * handle, + semanage_fcontext_t ** fcontext) +{ + + semanage_fcontext_t *tmp_fcontext = + (semanage_fcontext_t *) malloc(sizeof(semanage_fcontext_t)); + + if (!tmp_fcontext) { + ERR(handle, "out of memory, could not create " + "file context record"); + return STATUS_ERR; + } + + tmp_fcontext->expr = NULL; + tmp_fcontext->type = SEMANAGE_FCONTEXT_ALL; + tmp_fcontext->con = NULL; + *fcontext = tmp_fcontext; + + return STATUS_SUCCESS; +} + +hidden_def(semanage_fcontext_create) + +/* Regexp */ +const char *semanage_fcontext_get_expr(const semanage_fcontext_t * fcontext) +{ + + return fcontext->expr; +} + +hidden_def(semanage_fcontext_get_expr) + +int semanage_fcontext_set_expr(semanage_handle_t * handle, + semanage_fcontext_t * fcontext, const char *expr) +{ + + char *tmp_expr = strdup(expr); + if (!tmp_expr) { + ERR(handle, "out of memory, " "could not set regexp string"); + return STATUS_ERR; + } + free(fcontext->expr); + fcontext->expr = tmp_expr; + return STATUS_SUCCESS; +} + +hidden_def(semanage_fcontext_set_expr) + +/* Type */ +int semanage_fcontext_get_type(const semanage_fcontext_t * fcontext) +{ + + return fcontext->type; +} + +hidden_def(semanage_fcontext_get_type) + +const char *semanage_fcontext_get_type_str(int type) +{ + + switch (type) { + case SEMANAGE_FCONTEXT_ALL: + return "all files"; + case SEMANAGE_FCONTEXT_REG: + return "regular file"; + case SEMANAGE_FCONTEXT_DIR: + return "directory"; + case SEMANAGE_FCONTEXT_CHAR: + return "character device"; + case SEMANAGE_FCONTEXT_BLOCK: + return "block device"; + case SEMANAGE_FCONTEXT_SOCK: + return "socket"; + case SEMANAGE_FCONTEXT_LINK: + return "symbolic link"; + case SEMANAGE_FCONTEXT_PIPE: + return "named pipe"; + default: + return "????"; + } +} + +hidden_def(semanage_fcontext_get_type_str) + +void semanage_fcontext_set_type(semanage_fcontext_t * fcontext, int type) +{ + + fcontext->type = type; +} + +hidden_def(semanage_fcontext_set_type) + +/* Context */ +semanage_context_t *semanage_fcontext_get_con(const semanage_fcontext_t * + fcontext) +{ + + return fcontext->con; +} + +hidden_def(semanage_fcontext_get_con) + +int semanage_fcontext_set_con(semanage_handle_t * handle, + semanage_fcontext_t * fcontext, + semanage_context_t * con) +{ + + semanage_context_t *newcon; + + if (semanage_context_clone(handle, con, &newcon) < 0) { + ERR(handle, "out of memory, could not set file context"); + return STATUS_ERR; + } + + semanage_context_free(fcontext->con); + fcontext->con = newcon; + return STATUS_SUCCESS; +} + +hidden_def(semanage_fcontext_set_con) + +/* Deep copy clone */ +int semanage_fcontext_clone(semanage_handle_t * handle, + const semanage_fcontext_t * fcontext, + semanage_fcontext_t ** fcontext_ptr) +{ + + semanage_fcontext_t *new_fcontext = NULL; + if (semanage_fcontext_create(handle, &new_fcontext) < 0) + goto err; + + if (semanage_fcontext_set_expr(handle, new_fcontext, fcontext->expr) < + 0) + goto err; + + new_fcontext->type = fcontext->type; + + if (fcontext->con && + (semanage_context_clone(handle, fcontext->con, &new_fcontext->con) < + 0)) + goto err; + + *fcontext_ptr = new_fcontext; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not clone file context record"); + semanage_fcontext_free(new_fcontext); + return STATUS_ERR; +} + +hidden_def(semanage_fcontext_clone) + +/* Destroy */ +void semanage_fcontext_free(semanage_fcontext_t * fcontext) +{ + + if (!fcontext) + return; + + free(fcontext->expr); + semanage_context_free(fcontext->con); + free(fcontext); +} + +hidden_def(semanage_fcontext_free) + +/* Record base functions */ +record_table_t SEMANAGE_FCONTEXT_RTABLE = { + .create = semanage_fcontext_create, + .key_extract = semanage_fcontext_key_extract, + .key_free = semanage_fcontext_key_free, + .clone = semanage_fcontext_clone, + .compare = semanage_fcontext_compare, + .compare2 = semanage_fcontext_compare2, + .compare2_qsort = semanage_fcontext_compare2_qsort, + .free = semanage_fcontext_free, +};
diff --git a/selinux/libsemanage/src/fcontexts_file.c b/selinux/libsemanage/src/fcontexts_file.c new file mode 100644 index 0000000..1e59651 --- /dev/null +++ b/selinux/libsemanage/src/fcontexts_file.c
@@ -0,0 +1,189 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_fcontext; +struct semanage_fcontext_key; +typedef struct semanage_fcontext record_t; +typedef struct semanage_fcontext_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <semanage/handle.h> +#include "fcontext_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static const char *type_str(int type) +{ + switch (type) { + default: + case SEMANAGE_FCONTEXT_ALL: + return " "; + case SEMANAGE_FCONTEXT_REG: + return "--"; + case SEMANAGE_FCONTEXT_DIR: + return "-d"; + case SEMANAGE_FCONTEXT_CHAR: + return "-c"; + case SEMANAGE_FCONTEXT_BLOCK: + return "-b"; + case SEMANAGE_FCONTEXT_SOCK: + return "-s"; + case SEMANAGE_FCONTEXT_LINK: + return "-l"; + case SEMANAGE_FCONTEXT_PIPE: + return "-p"; + } +} + +static int fcontext_print(semanage_handle_t * handle, + semanage_fcontext_t * fcontext, FILE * str) +{ + + char *con_str = NULL; + + const char *expr = semanage_fcontext_get_expr(fcontext); + int type = semanage_fcontext_get_type(fcontext); + const char *print_str = type_str(type); + const char *tstr = semanage_fcontext_get_type_str(type); + semanage_context_t *con = semanage_fcontext_get_con(fcontext); + + if (fprintf(str, "%s %s ", expr, print_str) < 0) + goto err; + + if (con != NULL) { + if (semanage_context_to_string(handle, con, &con_str) < 0) + goto err; + if (fprintf(str, "%s\n", con_str) < 0) + goto err; + free(con_str); + con_str = NULL; + } else { + if (fprintf(str, "<<none>>\n") < 0) + goto err; + } + return STATUS_SUCCESS; + + err: + ERR(handle, "could not print file context for " + "%s (%s) to stream", expr, tstr); + free(con_str); + return STATUS_ERR; +} + +static int fcontext_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_fcontext_t * fcontext) +{ + + char *str = NULL; + semanage_context_t *con = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Regexp */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_fcontext_set_expr(handle, fcontext, str) < 0) + goto err; + free(str); + str = NULL; + + /* Type */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (!strcasecmp(str, "-s")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_SOCK); + else if (!strcasecmp(str, "-p")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_PIPE); + else if (!strcasecmp(str, "-b")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_BLOCK); + else if (!strcasecmp(str, "-l")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_LINK); + else if (!strcasecmp(str, "-c")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_CHAR); + else if (!strcasecmp(str, "-d")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_DIR); + else if (!strcasecmp(str, "--")) + semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_REG); + else + goto process_context; + free(str); + str = NULL; + + /* Context */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + + process_context: + if (semanage_context_from_string(handle, str, &con) < 0) { + ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s", + str, info->filename, info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (con && semanage_fcontext_set_con(handle, fcontext, con) < 0) + goto err; + + if (parse_assert_space(handle, info) < 0) + goto err; + + semanage_context_free(con); + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse file context record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* FCONTEXT RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_FCONTEXT_FILE_RTABLE = { + .parse = fcontext_parse, + .print = fcontext_print, +}; + +int fcontext_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_FCONTEXT_RTABLE, + &SEMANAGE_FCONTEXT_FILE_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void fcontext_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/fcontexts_local.c b/selinux/libsemanage/src/fcontexts_local.c new file mode 100644 index 0000000..b0da236 --- /dev/null +++ b/selinux/libsemanage/src/fcontexts_local.c
@@ -0,0 +1,129 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_fcontext; +struct semanage_fcontext_key; +typedef struct semanage_fcontext_key record_key_t; +typedef struct semanage_fcontext record_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include <sepol/policydb.h> +#include <sepol/context.h> +#include "fcontext_internal.h" +#include "context_internal.h" +#include "debug.h" +#include "handle.h" +#include "database.h" + +int semanage_fcontext_modify_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + const semanage_fcontext_t * data) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_fcontext_del_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_fcontext_query_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + semanage_fcontext_t ** response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_fcontext_exists_local(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + int *response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_fcontext_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_fcontext_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_fcontext_t * + record, void *varg), + void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +hidden_def(semanage_fcontext_iterate_local) + +int semanage_fcontext_list_local(semanage_handle_t * handle, + semanage_fcontext_t *** records, + unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +} + +struct validate_handler_arg { + semanage_handle_t *handle; + const sepol_policydb_t *policydb; +}; + +static int validate_handler(const semanage_fcontext_t * fcon, void *varg) +{ + + char *str; + + /* Unpack varg */ + struct validate_handler_arg *arg = (struct validate_handler_arg *)varg; + semanage_handle_t *handle = arg->handle; + const sepol_policydb_t *policydb = arg->policydb; + + /* Unpack fcontext */ + const char *expr = semanage_fcontext_get_expr(fcon); + int type = semanage_fcontext_get_type(fcon); + const char *type_str = semanage_fcontext_get_type_str(type); + semanage_context_t *con = semanage_fcontext_get_con(fcon); + + if (con + && sepol_context_check(handle->sepolh, policydb, + (sepol_context_t *) con) < 0) + goto invalid; + + return 0; + + invalid: + if (semanage_context_to_string(handle, con, &str) >= 0) { + ERR(handle, "invalid context %s specified for %s [%s]", + str, expr, type_str); + free(str); + } else + ERR(handle, "invalid context specified for %s [%s]", + expr, type_str); + return -1; +} + +int hidden semanage_fcontext_validate_local(semanage_handle_t * handle, + const sepol_policydb_t * policydb) +{ + + struct validate_handler_arg arg; + arg.handle = handle; + arg.policydb = policydb; + return semanage_fcontext_iterate_local(handle, validate_handler, &arg); +}
diff --git a/selinux/libsemanage/src/fcontexts_policy.c b/selinux/libsemanage/src/fcontexts_policy.c new file mode 100644 index 0000000..0b063b1 --- /dev/null +++ b/selinux/libsemanage/src/fcontexts_policy.c
@@ -0,0 +1,53 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_fcontext; +struct semanage_fcontext_key; +typedef struct semanage_fcontext_key record_key_t; +typedef struct semanage_fcontext record_t; +#define DBASE_RECORD_DEFINED + +#include "fcontext_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_fcontext_query(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, + semanage_fcontext_t ** response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_fcontext_exists(semanage_handle_t * handle, + const semanage_fcontext_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_fcontext_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_fcontext_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_fcontext_t * + record, void *varg), + void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_fcontext_list(semanage_handle_t * handle, + semanage_fcontext_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/genhomedircon.c b/selinux/libsemanage/src/genhomedircon.c new file mode 100644 index 0000000..c5ea436 --- /dev/null +++ b/selinux/libsemanage/src/genhomedircon.c
@@ -0,0 +1,1144 @@ +/* Author: Mark Goldman <mgoldman@tresys.com> + * Paul Rosenfeld <prosenfeld@tresys.com> + * Todd C. Miller <tmiller@tresys.com> + * + * Copyright (C) 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 <semanage/handle.h> +#include <semanage/seusers_policy.h> +#include <semanage/users_policy.h> +#include <semanage/user_record.h> +#include <semanage/fcontext_record.h> +#include <semanage/fcontexts_policy.h> +#include <sepol/context.h> +#include <sepol/context_record.h> +#include "semanage_store.h" +#include "seuser_internal.h" +#include "debug.h" + +#include "utilities.h" +#include "genhomedircon.h" +#include <ustr.h> + +#include <assert.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pwd.h> +#include <errno.h> +#include <unistd.h> +#include <regex.h> + +/* paths used in get_home_dirs() */ +#define PATH_ETC_USERADD "/etc/default/useradd" +#define PATH_ETC_LIBUSER "/etc/libuser.conf" +#define PATH_DEFAULT_HOME "/home" +#define PATH_EXPORT_HOME "/export/home" +#define PATH_ETC_LOGIN_DEFS "/etc/login.defs" + +/* other paths */ +#define PATH_SHELLS_FILE "/etc/shells" +#define PATH_NOLOGIN_SHELL "/sbin/nologin" + +/* comments written to context file */ +#define COMMENT_FILE_CONTEXT_HEADER "#\n#\n# " \ + "User-specific file contexts, generated via libsemanage\n" \ + "# use semanage command to manage system users to change" \ + " the file_context\n#\n#\n" + +#define COMMENT_USER_HOME_CONTEXT "\n\n#\n# Home Context for user %s" \ + "\n#\n\n" + +/* placeholders used in the template file + which are searched for and replaced */ +#define TEMPLATE_HOME_ROOT "HOME_ROOT" +#define TEMPLATE_HOME_DIR "HOME_DIR" +/* these are legacy */ +#define TEMPLATE_USER "USER" +#define TEMPLATE_ROLE "ROLE" +/* new names */ +#define TEMPLATE_USERNAME "%{USERNAME}" +#define TEMPLATE_USERID "%{USERID}" + +#define TEMPLATE_SEUSER "system_u" +#define TEMPLATE_LEVEL "s0" + +#define FALLBACK_SENAME "user_u" +#define FALLBACK_PREFIX "user" +#define FALLBACK_LEVEL "s0" +#define FALLBACK_NAME "[^/]+" +#define FALLBACK_UIDGID "[0-9]+" +#define DEFAULT_LOGIN "__default__" + +typedef struct user_entry { + char *name; + char *uid; + char *gid; + char *sename; + char *prefix; + char *home; + char *level; + struct user_entry *next; +} genhomedircon_user_entry_t; + +typedef struct { + const char *fcfilepath; + int usepasswd; + const char *homedir_template_path; + genhomedircon_user_entry_t *fallback; + semanage_handle_t *h_semanage; + sepol_policydb_t *policydb; +} genhomedircon_settings_t; + +typedef struct { + const char *search_for; + const char *replace_with; +} replacement_pair_t; + +typedef struct { + const char *dir; + int matched; +} fc_match_handle_t; + +typedef struct IgnoreDir { + struct IgnoreDir *next; + char *dir; +} ignoredir_t; + +ignoredir_t *ignore_head = NULL; + +static void ignore_free(void) { + ignoredir_t *next; + + while (ignore_head) { + next = ignore_head->next; + free(ignore_head->dir); + free(ignore_head); + ignore_head = next; + } +} + +static int ignore_setup(char *ignoredirs) { + char *tok; + ignoredir_t *ptr = NULL; + + tok = strtok(ignoredirs, ";"); + while(tok) { + ptr = calloc(sizeof(ignoredir_t),1); + if (!ptr) + goto err; + ptr->dir = strdup(tok); + if (!ptr->dir) + goto err; + + ptr->next = ignore_head; + ignore_head = ptr; + + tok = strtok(NULL, ";"); + } + + return 0; +err: + free(ptr); + ignore_free(); + return -1; +} + +static int ignore(const char *homedir) { + ignoredir_t *ptr = ignore_head; + while (ptr) { + if (strcmp(ptr->dir, homedir) == 0) { + return 1; + } + ptr = ptr->next; + } + return 0; +} + +static semanage_list_t *default_shell_list(void) +{ + semanage_list_t *list = NULL; + + if (semanage_list_push(&list, "/bin/csh") + || semanage_list_push(&list, "/bin/tcsh") + || semanage_list_push(&list, "/bin/ksh") + || semanage_list_push(&list, "/bin/bsh") + || semanage_list_push(&list, "/bin/ash") + || semanage_list_push(&list, "/usr/bin/ksh") + || semanage_list_push(&list, "/usr/bin/pdksh") + || semanage_list_push(&list, "/bin/zsh") + || semanage_list_push(&list, "/bin/sh") + || semanage_list_push(&list, "/bin/bash")) + goto fail; + + return list; + + fail: + semanage_list_destroy(&list); + return NULL; +} + +static semanage_list_t *get_shell_list(void) +{ + FILE *shells; + char *temp = NULL; + semanage_list_t *list = NULL; + size_t buff_len = 0; + ssize_t len; + + shells = fopen(PATH_SHELLS_FILE, "r"); + if (!shells) + return default_shell_list(); + while ((len = getline(&temp, &buff_len, shells)) > 0) { + if (temp[len-1] == '\n') temp[len-1] = 0; + if (strcmp(temp, PATH_NOLOGIN_SHELL)) { + if (semanage_list_push(&list, temp)) { + free(temp); + semanage_list_destroy(&list); + return default_shell_list(); + } + } + } + free(temp); + + return list; +} + +/* Helper function called via semanage_fcontext_iterate() */ +static int fcontext_matches(const semanage_fcontext_t *fcontext, void *varg) +{ + const char *oexpr = semanage_fcontext_get_expr(fcontext); + fc_match_handle_t *handp = varg; + struct Ustr *expr; + regex_t re; + int type, retval = -1; + + /* Only match ALL or DIR */ + type = semanage_fcontext_get_type(fcontext); + if (type != SEMANAGE_FCONTEXT_ALL && type != SEMANAGE_FCONTEXT_ALL) + return 0; + + /* Convert oexpr into a Ustr and anchor it at the beginning */ + expr = ustr_dup_cstr("^"); + if (expr == USTR_NULL) + goto done; + if (!ustr_add_cstr(&expr, oexpr)) + goto done; + + /* Strip off trailing ".+" or ".*" */ + if (ustr_cmp_suffix_cstr_eq(expr, ".+") || + ustr_cmp_suffix_cstr_eq(expr, ".*")) { + if (!ustr_del(&expr, 2)) + goto done; + } + + /* Strip off trailing "(/.*)?" */ + if (ustr_cmp_suffix_cstr_eq(expr, "(/.*)?")) { + if (!ustr_del(&expr, 6)) + goto done; + } + + if (ustr_cmp_suffix_cstr_eq(expr, "/")) { + if (!ustr_del(&expr, 1)) + goto done; + } + + /* Append pattern to eat up trailing slashes */ + if (!ustr_add_cstr(&expr, "/*$")) + goto done; + + /* Check dir against expr */ + if (regcomp(&re, ustr_cstr(expr), REG_EXTENDED) != 0) + goto done; + if (regexec(&re, handp->dir, 0, NULL, 0) == 0) + handp->matched = 1; + regfree(&re); + + retval = 0; + +done: + ustr_free(expr); + + return retval; +} + +static semanage_list_t *get_home_dirs(genhomedircon_settings_t * s) +{ + semanage_list_t *homedir_list = NULL; + semanage_list_t *shells = NULL; + fc_match_handle_t hand; + char *rbuf = NULL; + char *path = NULL; + long rbuflen; + uid_t temp, minuid = 500, maxuid = 60000; + int minuid_set = 0; + struct passwd pwstorage, *pwbuf; + struct stat buf; + int retval; + + path = semanage_findval(PATH_ETC_USERADD, "HOME", "="); + if (path && *path) { + if (semanage_list_push(&homedir_list, path)) + goto fail; + } + free(path); + + path = semanage_findval(PATH_ETC_LIBUSER, "LU_HOMEDIRECTORY", "="); + if (path && *path) { + if (semanage_list_push(&homedir_list, path)) + goto fail; + } + free(path); + path = NULL; + + if (!homedir_list) { + if (semanage_list_push(&homedir_list, PATH_DEFAULT_HOME)) { + goto fail; + } + } + + if (!stat(PATH_EXPORT_HOME, &buf)) { + if (S_ISDIR(buf.st_mode)) { + if (semanage_list_push(&homedir_list, PATH_EXPORT_HOME)) { + goto fail; + } + } + } + + if (!(s->usepasswd)) + return homedir_list; + + shells = get_shell_list(); + assert(shells); + + path = semanage_findval(PATH_ETC_LOGIN_DEFS, "UID_MIN", NULL); + if (path && *path) { + temp = atoi(path); + minuid = temp; + minuid_set = 1; + } + free(path); + path = NULL; + + path = semanage_findval(PATH_ETC_LOGIN_DEFS, "UID_MAX", NULL); + if (path && *path) { + temp = atoi(path); + maxuid = temp; + } + free(path); + path = NULL; + + path = semanage_findval(PATH_ETC_LIBUSER, "LU_UIDNUMBER", "="); + if (path && *path) { + temp = atoi(path); + if (!minuid_set || temp < minuid) { + minuid = temp; + minuid_set = 1; + } + } + free(path); + path = NULL; + + rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen <= 0) + goto fail; + rbuf = malloc(rbuflen); + if (rbuf == NULL) + goto fail; + setpwent(); + while ((retval = getpwent_r(&pwstorage, rbuf, rbuflen, &pwbuf)) == 0) { + if (pwbuf->pw_uid < minuid || pwbuf->pw_uid > maxuid) + continue; + if (!semanage_list_find(shells, pwbuf->pw_shell)) + continue; + int len = strlen(pwbuf->pw_dir) -1; + for(; len > 0 && pwbuf->pw_dir[len] == '/'; len--) { + pwbuf->pw_dir[len] = '\0'; + } + if (strcmp(pwbuf->pw_dir, "/") == 0) + continue; + if (ignore(pwbuf->pw_dir)) + continue; + if (semanage_str_count(pwbuf->pw_dir, '/') <= 1) + continue; + if (!(path = strdup(pwbuf->pw_dir))) { + break; + } + + semanage_rtrim(path, '/'); + + if (!semanage_list_find(homedir_list, path)) { + /* + * Now check for an existing file context that matches + * so we don't label a non-homedir as a homedir. + */ + hand.dir = path; + hand.matched = 0; + if (semanage_fcontext_iterate(s->h_semanage, + fcontext_matches, &hand) == STATUS_ERR) + goto fail; + + /* NOTE: old genhomedircon printed a warning on match */ + if (hand.matched) { + WARN(s->h_semanage, "%s homedir %s or its parent directory conflicts with a file context already specified in the policy. This usually indicates an incorrectly defined system account. If it is a system account please make sure its uid is less than %u or greater than %u or its login shell is /sbin/nologin.", pwbuf->pw_name, pwbuf->pw_dir, minuid, maxuid); + } else { + if (semanage_list_push(&homedir_list, path)) + goto fail; + } + } + free(path); + path = NULL; + } + + if (retval && retval != ENOENT) { + WARN(s->h_semanage, "Error while fetching users. " + "Returning list so far."); + } + + if (semanage_list_sort(&homedir_list)) + goto fail; + + endpwent(); + free(rbuf); + semanage_list_destroy(&shells); + + return homedir_list; + + fail: + endpwent(); + free(rbuf); + free(path); + semanage_list_destroy(&homedir_list); + semanage_list_destroy(&shells); + return NULL; +} + +/** + * @param out the FILE to put all the output in. + * @return 0 on success + */ +static int write_file_context_header(FILE * out) +{ + if (fprintf(out, COMMENT_FILE_CONTEXT_HEADER) < 0) { + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +/* Predicates for use with semanage_slurp_file_filter() the homedir_template + * file currently contains lines that serve as the template for a user's + * homedir. + * + * It also contains lines that are the template for the parent of a + * user's home directory. + * + * Currently, the only lines that apply to the the root of a user's home + * directory are all prefixed with the string "HOME_ROOT". All other + * lines apply to a user's home directory. If this changes the + * following predicates need to change to reflect that. + */ +static int HOME_ROOT_PRED(const char *string) +{ + return semanage_is_prefix(string, TEMPLATE_HOME_ROOT); +} + +static int HOME_DIR_PRED(const char *string) +{ + return semanage_is_prefix(string, TEMPLATE_HOME_DIR); +} + +/* new names */ +static int USERNAME_CONTEXT_PRED(const char *string) +{ + return (int)( + (strstr(string, TEMPLATE_USERNAME) != NULL) || + (strstr(string, TEMPLATE_USERID) != NULL) + ); +} + +/* This will never match USER if USERNAME or USERID are found. */ +static int USER_CONTEXT_PRED(const char *string) +{ + if (USERNAME_CONTEXT_PRED(string)) + return 0; + + return (int)(strstr(string, TEMPLATE_USER) != NULL); +} + +/* make_tempate + * @param s the settings holding the paths to various files + * @param pred function pointer to function to use as filter for slurp + * file filter + * @return a list of lines from the template file with inappropriate + * lines filtered out. + */ +static semanage_list_t *make_template(genhomedircon_settings_t * s, + int (*pred) (const char *)) +{ + FILE *template_file = NULL; + semanage_list_t *template_data = NULL; + + template_file = fopen(s->homedir_template_path, "r"); + if (!template_file) + return NULL; + template_data = semanage_slurp_file_filter(template_file, pred); + fclose(template_file); + + return template_data; +} + +static Ustr *replace_all(const char *str, const replacement_pair_t * repl) +{ + Ustr *retval = USTR_NULL; + int i; + + if (!str || !repl) + goto done; + if (!(retval = ustr_dup_cstr(str))) + goto done; + + for (i = 0; repl[i].search_for; i++) { + ustr_replace_cstr(&retval, repl[i].search_for, + repl[i].replace_with, 0); + } + if (ustr_enomem(retval)) + ustr_sc_free(&retval); + + done: + return retval; +} + +static const char * extract_context(Ustr *line) +{ + const char whitespace[] = " \t\n"; + size_t off, len; + + /* check for trailing whitespace */ + off = ustr_spn_chrs_rev(line, 0, whitespace, strlen(whitespace)); + + /* find the length of the last field in line */ + len = ustr_cspn_chrs_rev(line, off, whitespace, strlen(whitespace)); + + if (len == 0) + return NULL; + return ustr_cstr(line) + ustr_len(line) - (len + off); +} + +static int check_line(genhomedircon_settings_t * s, Ustr *line) +{ + sepol_context_t *ctx_record = NULL; + const char *ctx_str; + int result; + + ctx_str = extract_context(line); + if (!ctx_str) + return STATUS_ERR; + + result = sepol_context_from_string(s->h_semanage->sepolh, + ctx_str, &ctx_record); + if (result == STATUS_SUCCESS && ctx_record != NULL) { + sepol_msg_set_callback(s->h_semanage->sepolh, NULL, NULL); + result = sepol_context_check(s->h_semanage->sepolh, + s->policydb, ctx_record); + sepol_msg_set_callback(s->h_semanage->sepolh, + semanage_msg_relay_handler, s->h_semanage); + sepol_context_free(ctx_record); + } + return result; +} + +static int write_replacements(genhomedircon_settings_t * s, FILE * out, + const semanage_list_t * tpl, + const replacement_pair_t *repl) +{ + Ustr *line = USTR_NULL; + + for (; tpl; tpl = tpl->next) { + line = replace_all(tpl->data, repl); + if (!line) + goto fail; + if (check_line(s, line) == STATUS_SUCCESS) { + if (!ustr_io_putfileline(&line, out)) + goto fail; + } + ustr_sc_free(&line); + } + return STATUS_SUCCESS; + + fail: + ustr_sc_free(&line); + return STATUS_ERR; +} + +static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, const genhomedircon_user_entry_t *user) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, + {.search_for = TEMPLATE_HOME_DIR,.replace_with = user->home}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_LEVEL,.replace_with = user->level}, + {NULL, NULL} + }; + + if (strcmp(user->name, FALLBACK_NAME) == 0) { + if (fprintf(out, COMMENT_USER_HOME_CONTEXT, FALLBACK_SENAME) < 0) + return STATUS_ERR; + } else { + if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user->name) < 0) + return STATUS_ERR; + } + + return write_replacements(s, out, tpl, repl); +} + +static int write_home_root_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, char *homedir) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_HOME_ROOT,.replace_with = homedir}, + {NULL, NULL} + }; + + return write_replacements(s, out, tpl, repl); +} + +static int write_username_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, + const genhomedircon_user_entry_t *user) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_USERNAME,.replace_with = user->name}, + {.search_for = TEMPLATE_USERID,.replace_with = user->uid}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, + {NULL, NULL} + }; + + return write_replacements(s, out, tpl, repl); +} + +static int write_user_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, const genhomedircon_user_entry_t *user) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_USER,.replace_with = user->name}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, + {NULL, NULL} + }; + + return write_replacements(s, out, tpl, repl); +} + +static int user_sort_func(semanage_user_t ** arg1, semanage_user_t ** arg2) +{ + return strcmp(semanage_user_get_name(*arg1), + semanage_user_get_name(*arg2)); +} + +static int name_user_cmp(char *key, semanage_user_t ** val) +{ + return strcmp(key, semanage_user_get_name(*val)); +} + +static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n, + const char *u, const char *g, const char *sen, + const char *pre, const char *h, const char *l) +{ + genhomedircon_user_entry_t *temp = NULL; + char *name = NULL; + char *uid = NULL; + char *gid = NULL; + char *sename = NULL; + char *prefix = NULL; + char *home = NULL; + char *level = NULL; + + temp = malloc(sizeof(genhomedircon_user_entry_t)); + if (!temp) + goto cleanup; + name = strdup(n); + if (!name) + goto cleanup; + uid = strdup(u); + if (!uid) + goto cleanup; + gid = strdup(g); + if (!gid) + goto cleanup; + sename = strdup(sen); + if (!sename) + goto cleanup; + prefix = strdup(pre); + if (!prefix) + goto cleanup; + home = strdup(h); + if (!home) + goto cleanup; + level = strdup(l); + if (!level) + goto cleanup; + + temp->name = name; + temp->uid = uid; + temp->gid = gid; + temp->sename = sename; + temp->prefix = prefix; + temp->home = home; + temp->level = level; + temp->next = (*list); + (*list) = temp; + + return STATUS_SUCCESS; + + cleanup: + free(name); + free(uid); + free(gid); + free(sename); + free(prefix); + free(home); + free(level); + free(temp); + return STATUS_ERR; +} + +static void pop_user_entry(genhomedircon_user_entry_t ** list) +{ + genhomedircon_user_entry_t *temp; + + if (!list || !(*list)) + return; + + temp = *list; + *list = temp->next; + free(temp->name); + free(temp->uid); + free(temp->gid); + free(temp->sename); + free(temp->prefix); + free(temp->home); + free(temp->level); + free(temp); +} + +static int setup_fallback_user(genhomedircon_settings_t * s) +{ + semanage_seuser_t **seuser_list = NULL; + unsigned int nseusers = 0; + semanage_user_key_t *key = NULL; + semanage_user_t *u = NULL; + const char *name = NULL; + const char *seuname = NULL; + const char *prefix = NULL; + const char *level = NULL; + unsigned int i; + int retval; + int errors = 0; + + retval = semanage_seuser_list(s->h_semanage, &seuser_list, &nseusers); + if (retval < 0 || (nseusers < 1)) { + /* if there are no users, this function can't do any other work */ + return errors; + } + + for (i = 0; i < nseusers; i++) { + name = semanage_seuser_get_name(seuser_list[i]); + if (strcmp(name, DEFAULT_LOGIN) == 0) { + seuname = semanage_seuser_get_sename(seuser_list[i]); + + /* find the user structure given the name */ + if (semanage_user_key_create(s->h_semanage, seuname, + &key) < 0) { + errors = STATUS_ERR; + break; + } + if (semanage_user_query(s->h_semanage, key, &u) < 0) + { + prefix = name; + level = FALLBACK_LEVEL; + } + else + { + prefix = semanage_user_get_prefix(u); + level = semanage_user_get_mlslevel(u); + if (!level) + level = FALLBACK_LEVEL; + } + + if (push_user_entry(&(s->fallback), FALLBACK_NAME, + FALLBACK_UIDGID, FALLBACK_UIDGID, + seuname, prefix, "", level) != 0) + errors = STATUS_ERR; + semanage_user_key_free(key); + if (u) + semanage_user_free(u); + break; + } + } + + for (i = 0; i < nseusers; i++) + semanage_seuser_free(seuser_list[i]); + free(seuser_list); + + return errors; +} + +static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s, + int *errors) +{ + genhomedircon_user_entry_t *head = NULL; + semanage_seuser_t **seuser_list = NULL; + unsigned int nseusers = 0; + semanage_user_t **user_list = NULL; + unsigned int nusers = 0; + semanage_user_t **u = NULL; + const char *name = NULL; + const char *seuname = NULL; + const char *prefix = NULL; + const char *level = NULL; + char uid[11]; + char gid[11]; + struct passwd pwstorage, *pwent = NULL; + unsigned int i; + long rbuflen; + char *rbuf = NULL; + int retval; + + *errors = 0; + retval = semanage_seuser_list(s->h_semanage, &seuser_list, &nseusers); + if (retval < 0 || (nseusers < 1)) { + /* if there are no users, this function can't do any other work */ + return NULL; + } + + if (semanage_user_list(s->h_semanage, &user_list, &nusers) < 0) { + nusers = 0; + } + + qsort(user_list, nusers, sizeof(semanage_user_t *), + (int (*)(const void *, const void *))&user_sort_func); + + /* Allocate space for the getpwnam_r buffer */ + rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen <= 0) + goto cleanup; + rbuf = malloc(rbuflen); + if (rbuf == NULL) + goto cleanup; + + for (i = 0; i < nseusers; i++) { + seuname = semanage_seuser_get_sename(seuser_list[i]); + name = semanage_seuser_get_name(seuser_list[i]); + + if (strcmp(name,"root") && strcmp(seuname, s->fallback->sename) == 0) + continue; + + if (strcmp(name, DEFAULT_LOGIN) == 0) + continue; + + if (strcmp(name, TEMPLATE_SEUSER) == 0) + continue; + + /* %groupname syntax */ + if (name[0] == '%') + continue; + + /* find the user structure given the name */ + u = bsearch(seuname, user_list, nusers, sizeof(semanage_user_t *), + (int (*)(const void *, const void *)) + &name_user_cmp); + if (u) { + prefix = semanage_user_get_prefix(*u); + level = semanage_user_get_mlslevel(*u); + if (!level) + level = FALLBACK_LEVEL; + } else { + prefix = name; + level = FALLBACK_LEVEL; + } + + retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (retval != 0 || pwent == NULL) { + if (retval != 0 && retval != ENOENT) { + *errors = STATUS_ERR; + goto cleanup; + } + + WARN(s->h_semanage, + "user %s not in password file", name); + continue; + } + + int len = strlen(pwent->pw_dir) -1; + for(; len > 0 && pwent->pw_dir[len] == '/'; len--) { + pwent->pw_dir[len] = '\0'; + } + + if (strcmp(pwent->pw_dir, "/") == 0) { + /* don't relabel / genhomdircon checked to see if root + * was the user and if so, set his home directory to + * /root */ + continue; + } + if (ignore(pwent->pw_dir)) + continue; + + len = snprintf(uid, sizeof(uid), "%u", pwent->pw_uid); + if (len < 0 || len >= (int)sizeof(uid)) { + *errors = STATUS_ERR; + goto cleanup; + } + len = snprintf(gid, sizeof(gid), "%u", pwent->pw_gid); + if (len < 0 || len >= (int)sizeof(gid)) { + *errors = STATUS_ERR; + goto cleanup; + } + + if (push_user_entry(&head, name, uid, gid, seuname, + prefix, pwent->pw_dir, level) != STATUS_SUCCESS) { + *errors = STATUS_ERR; + break; + } + } + + cleanup: + free(rbuf); + if (*errors) { + for (; head; pop_user_entry(&head)) { + /* the pop function takes care of all the cleanup + so the loop body is just empty */ + } + } + for (i = 0; i < nseusers; i++) { + semanage_seuser_free(seuser_list[i]); + } + free(seuser_list); + + for (i = 0; i < nusers; i++) { + semanage_user_free(user_list[i]); + } + free(user_list); + + return head; +} + +static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * username_context_tpl, + semanage_list_t * user_context_tpl, + semanage_list_t * homedir_context_tpl) +{ + genhomedircon_user_entry_t *users; + int errors = 0; + + users = get_users(s, &errors); + if (!users && errors) { + return STATUS_ERR; + } + + for (; users; pop_user_entry(&users)) { + if (write_home_dir_context(s, out, homedir_context_tpl, users)) + goto err; + if (write_username_context(s, out, username_context_tpl, users)) + goto err; + if (write_user_context(s, out, user_context_tpl, users)) + goto err; + } + + return STATUS_SUCCESS; +err: + for (; users; pop_user_entry(&users)) { + /* the pop function takes care of all the cleanup + * so the loop body is just empty */ + } + + return STATUS_ERR; +} + +/** + * @param s settings structure, stores various paths etc. Must never be NULL + * @param out the FILE to put all the output in. + * @return 0 on success + */ +static int write_context_file(genhomedircon_settings_t * s, FILE * out) +{ + semanage_list_t *homedirs = NULL; + semanage_list_t *h = NULL; + semanage_list_t *homedir_context_tpl = NULL; + semanage_list_t *homeroot_context_tpl = NULL; + semanage_list_t *username_context_tpl = NULL; + semanage_list_t *user_context_tpl = NULL; + int retval = STATUS_SUCCESS; + + homedir_context_tpl = make_template(s, &HOME_DIR_PRED); + homeroot_context_tpl = make_template(s, &HOME_ROOT_PRED); + username_context_tpl = make_template(s, &USERNAME_CONTEXT_PRED); + user_context_tpl = make_template(s, &USER_CONTEXT_PRED); + + if (!homedir_context_tpl + && !homeroot_context_tpl + && !username_context_tpl + && !user_context_tpl) + goto done; + + if (write_file_context_header(out) != STATUS_SUCCESS) { + retval = STATUS_ERR; + goto done; + } + + if (setup_fallback_user(s) != 0) { + retval = STATUS_ERR; + goto done; + } + + if (homedir_context_tpl || homeroot_context_tpl) { + homedirs = get_home_dirs(s); + if (!homedirs) { + WARN(s->h_semanage, + "no home directories were available, exiting without writing"); + goto done; + } + + for (h = homedirs; h; h = h->next) { + Ustr *temp = ustr_dup_cstr(h->data); + + if (!temp || !ustr_add_cstr(&temp, "/" FALLBACK_NAME)) { + ustr_sc_free(&temp); + retval = STATUS_ERR; + goto done; + } + + free(s->fallback->home); + s->fallback->home = (char*) ustr_cstr(temp); + + if (write_home_dir_context(s, out, homedir_context_tpl, + s->fallback) != STATUS_SUCCESS) { + ustr_sc_free(&temp); + s->fallback->home = NULL; + retval = STATUS_ERR; + goto done; + } + if (write_home_root_context(s, out, + homeroot_context_tpl, + h->data) != STATUS_SUCCESS) { + ustr_sc_free(&temp); + s->fallback->home = NULL; + retval = STATUS_ERR; + goto done; + } + + ustr_sc_free(&temp); + s->fallback->home = NULL; + } + } + if (user_context_tpl || username_context_tpl) { + if (write_username_context(s, out, username_context_tpl, + s->fallback) != STATUS_SUCCESS) { + retval = STATUS_ERR; + goto done; + } + + if (write_user_context(s, out, user_context_tpl, + s->fallback) != STATUS_SUCCESS) { + retval = STATUS_ERR; + goto done; + } + + if (write_gen_home_dir_context(s, out, username_context_tpl, + user_context_tpl, homedir_context_tpl) + != STATUS_SUCCESS) { + retval = STATUS_ERR; + } + } + +done: + /* Cleanup */ + semanage_list_destroy(&homedirs); + semanage_list_destroy(&username_context_tpl); + semanage_list_destroy(&user_context_tpl); + semanage_list_destroy(&homedir_context_tpl); + semanage_list_destroy(&homeroot_context_tpl); + + return retval; +} + +int semanage_genhomedircon(semanage_handle_t * sh, + sepol_policydb_t * policydb, + int usepasswd, + char *ignoredirs) +{ + genhomedircon_settings_t s; + FILE *out = NULL; + int retval = 0; + + assert(sh); + + s.homedir_template_path = + semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL); + s.fcfilepath = semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FC_HOMEDIRS); + + s.fallback = calloc(1, sizeof(genhomedircon_user_entry_t)); + if (s.fallback == NULL) { + retval = STATUS_ERR; + goto done; + } + + s.fallback->name = strdup(FALLBACK_NAME); + s.fallback->sename = strdup(FALLBACK_SENAME); + s.fallback->prefix = strdup(FALLBACK_PREFIX); + s.fallback->level = strdup(FALLBACK_LEVEL); + if (s.fallback->name == NULL + || s.fallback->sename == NULL + || s.fallback->prefix == NULL + || s.fallback->level == NULL) { + retval = STATUS_ERR; + goto done; + } + + if (ignoredirs) ignore_setup(ignoredirs); + + s.usepasswd = usepasswd; + s.h_semanage = sh; + s.policydb = policydb; + + if (!(out = fopen(s.fcfilepath, "w"))) { + /* couldn't open output file */ + ERR(sh, "Could not open the file_context file for writing"); + retval = STATUS_ERR; + goto done; + } + + retval = write_context_file(&s, out); + +done: + if (out != NULL) + fclose(out); + + pop_user_entry(&(s.fallback)); + ignore_free(); + + return retval; +}
diff --git a/selinux/libsemanage/src/genhomedircon.h b/selinux/libsemanage/src/genhomedircon.h new file mode 100644 index 0000000..3f9ef8f --- /dev/null +++ b/selinux/libsemanage/src/genhomedircon.h
@@ -0,0 +1,29 @@ +/* Author: Mark Goldman <mgoldman@tresys.com> + * + * Copyright (C) 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 _SEMANAGE_GENHOMEDIRCON_H_ +#define _SEMANAGE_GENHOMEDIRCON_H_ + +#include "utilities.h" + +int semanage_genhomedircon(semanage_handle_t * sh, + sepol_policydb_t * policydb, int usepasswd, + char *ignoredirs); + +#endif
diff --git a/selinux/libsemanage/src/handle.c b/selinux/libsemanage/src/handle.c new file mode 100644 index 0000000..4ce1df0 --- /dev/null +++ b/selinux/libsemanage/src/handle.c
@@ -0,0 +1,430 @@ +/* Author: Joshua Brindle <jbrindle@tresys.co + * Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This file implements only the publicly-visible handle functions to libsemanage. */ + +#include <selinux/selinux.h> + +#include <ctype.h> +#include <stdarg.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + +#include "direct_api.h" +#include "handle.h" +#include "debug.h" +#include "semanage_conf.h" +#include "semanage_store.h" + +#define SEMANAGE_COMMIT_READ_WAIT 5 + +static char *private_semanage_root = NULL; + +int semanage_set_root(const char *root) +{ + free(private_semanage_root); + private_semanage_root = strdup(root); + return 0; +} + +hidden_def(semanage_set_root); + +const char * semanage_root(void) +{ + if (private_semanage_root == NULL) { + return ""; + } + return private_semanage_root; +} + +semanage_handle_t *semanage_handle_create(void) +{ + semanage_handle_t *sh = NULL; + char *conf_name = NULL; + + /* Allocate handle */ + if ((sh = calloc(1, sizeof(semanage_handle_t))) == NULL) + goto err; + + if ((conf_name = semanage_conf_path()) == NULL) + goto err; + + if ((sh->conf = semanage_conf_parse(conf_name)) == NULL) + goto err; + + /* Link to sepol handle */ + sh->sepolh = sepol_handle_create(); + if (!sh->sepolh) + goto err; + sepol_msg_set_callback(sh->sepolh, semanage_msg_relay_handler, sh); + + /* Default priority is 400 */ + sh->priority = 400; + + /* By default do not rebuild the policy on commit + * If any changes are made, this flag is ignored */ + sh->do_rebuild = 0; + + /* By default always reload policy after commit if SELinux is enabled. */ + sh->do_reload = (is_selinux_enabled() > 0); + + /* By default always check the file contexts file. */ + sh->do_check_contexts = 1; + + /* By default do not create store */ + sh->create_store = 0; + + /* Set timeout: some default value for now, later use config */ + sh->timeout = SEMANAGE_COMMIT_READ_WAIT; + + /* Set callback */ + sh->msg_callback = semanage_msg_default_handler; + sh->msg_callback_arg = NULL; + + free(conf_name); + + return sh; + + err: + free(conf_name); + semanage_handle_destroy(sh); + return NULL; +} + +void semanage_set_rebuild(semanage_handle_t * sh, int do_rebuild) +{ + + assert(sh != NULL); + + sh->do_rebuild = do_rebuild; + return; +} + +void semanage_set_reload(semanage_handle_t * sh, int do_reload) +{ + + assert(sh != NULL); + + sh->do_reload = do_reload; + return; +} + +int semanage_get_hll_compiler_path(semanage_handle_t *sh, + char *lang_ext, + char **compiler_path) +{ + assert(sh != NULL); + assert(lang_ext != NULL); + + int i; + int status = 0; + int num_printed = 0; + size_t len; + char *compiler = NULL; + char *lower_lang_ext = NULL; + + lower_lang_ext = strdup(lang_ext); + if (lower_lang_ext == NULL) { + ERR(sh, "Could not create copy of lang_ext. Out of memory.\n"); + status = -1; + goto cleanup; + } + /* Set lang_ext to lowercase in case a file with a mixed case extension was passed to libsemanage */ + for (i = 0; lower_lang_ext[i] != '\0'; i++) { + lower_lang_ext[i] = tolower(lower_lang_ext[i]); + } + + len = strlen(sh->conf->compiler_directory_path) + strlen("/") + strlen(lower_lang_ext) + 1; + + compiler = malloc(len * sizeof(*compiler)); + if (compiler == NULL) { + ERR(sh, "Error allocating space for compiler path."); + status = -1; + goto cleanup; + } + + num_printed = snprintf(compiler, len, "%s/%s", sh->conf->compiler_directory_path, lower_lang_ext); + if (num_printed < 0 || (int)num_printed >= (int)len) { + ERR(sh, "Error creating compiler path."); + status = -1; + goto cleanup; + } + + *compiler_path = compiler; + status = 0; + +cleanup: + free(lower_lang_ext); + if (status != 0) { + free(compiler); + } + + return status; +} + +void semanage_set_create_store(semanage_handle_t * sh, int create_store) +{ + + assert(sh != NULL); + + sh->create_store = create_store; + return; +} + +int semanage_get_disable_dontaudit(semanage_handle_t * sh) +{ + assert(sh != NULL); + + return sepol_get_disable_dontaudit(sh->sepolh); +} + +void semanage_set_disable_dontaudit(semanage_handle_t * sh, int disable_dontaudit) +{ + assert(sh != NULL); + + sepol_set_disable_dontaudit(sh->sepolh, disable_dontaudit); + return; +} + +int semanage_get_preserve_tunables(semanage_handle_t * sh) +{ + assert(sh != NULL); + return sepol_get_preserve_tunables(sh->sepolh); +} + +void semanage_set_preserve_tunables(semanage_handle_t * sh, + int preserve_tunables) +{ + assert(sh != NULL); + sepol_set_preserve_tunables(sh->sepolh, preserve_tunables); +} + +int semanage_get_ignore_module_cache(semanage_handle_t *sh) +{ + assert(sh != NULL); + return sh->conf->ignore_module_cache; +} + +void semanage_set_ignore_module_cache(semanage_handle_t *sh, + int ignore_module_cache) +{ + assert(sh != NULL); + sh->conf->ignore_module_cache = ignore_module_cache; +} + +void semanage_set_check_contexts(semanage_handle_t * sh, int do_check_contexts) +{ + + assert(sh != NULL); + + sh->do_check_contexts = do_check_contexts; + return; +} + +uint16_t semanage_get_default_priority(semanage_handle_t *sh) +{ + assert(sh != NULL); + return sh->priority; +} + +int semanage_set_default_priority(semanage_handle_t *sh, uint16_t priority) +{ + assert(sh != NULL); + + /* Verify priority */ + if (semanage_module_validate_priority(priority) < 0) { + ERR(sh, "Priority %d is invalid.", priority); + return -1; + } + + sh->priority = priority; + return 0; +} + +int semanage_is_connected(semanage_handle_t * sh) +{ + assert(sh != NULL); + return sh->is_connected; +} + +void semanage_select_store(semanage_handle_t * sh, char *storename, + enum semanage_connect_type storetype) +{ + + assert(sh != NULL); + + /* This just sets the storename to what the user requests, no + verification of existance will be done until connect */ + free(sh->conf->store_path); + sh->conf->store_path = strdup(storename); + assert(sh->conf->store_path); /* no way to return failure */ + sh->conf->store_type = storetype; + + return; +} + +void semanage_set_store_root(semanage_handle_t *sh, const char *store_root) +{ + assert(sh != NULL); + + free(sh->conf->store_root_path); + sh->conf->store_root_path = strdup(store_root); + assert(sh->conf->store_root_path); /* no way to return failure */ + + return; +} + +int semanage_is_managed(semanage_handle_t * sh) +{ + assert(sh != NULL); + if (sh->is_connected) { + ERR(sh, "Already connected."); + return -1; + } + switch (sh->conf->store_type) { + case SEMANAGE_CON_DIRECT: + return semanage_direct_is_managed(sh); + default: + ERR(sh, + "The connection type specified within your semanage.conf file has not been implemented yet."); + /* fall through */ + } + return -1; +} + +int semanage_mls_enabled(semanage_handle_t * sh) +{ + assert(sh != NULL); + switch (sh->conf->store_type) { + case SEMANAGE_CON_DIRECT: + return semanage_direct_mls_enabled(sh); + default: + ERR(sh, + "The connection type specified within your semanage.conf file has not been implemented yet."); + /* fall through */ + } + return -1; +} + +int semanage_connect(semanage_handle_t * sh) +{ + assert(sh != NULL); + switch (sh->conf->store_type) { + case SEMANAGE_CON_DIRECT:{ + if (semanage_direct_connect(sh) < 0) { + return -1; + } + break; + } + default:{ + ERR(sh, + "The connection type specified within your semanage.conf file has not been implemented yet."); + return -1; + } + } + sh->is_connected = 1; + return 0; +} + +int semanage_access_check(semanage_handle_t * sh) +{ + assert(sh != NULL); + switch (sh->conf->store_type) { + case SEMANAGE_CON_DIRECT: + return semanage_direct_access_check(sh); + default: + return -1; + } + + return -1; /* unreachable */ +} + +hidden_def(semanage_access_check) + +int semanage_disconnect(semanage_handle_t * sh) +{ + assert(sh != NULL && sh->funcs != NULL + && sh->funcs->disconnect != NULL); + if (!sh->is_connected) { + return 0; + } + if (sh->funcs->disconnect(sh) < 0) { + return -1; + } + sh->is_in_transaction = 0; + sh->is_connected = 0; + sh->modules_modified = 0; + return 0; +} + +void semanage_handle_destroy(semanage_handle_t * sh) +{ + if (sh == NULL) + return; + + if (sh->funcs != NULL && sh->funcs->destroy != NULL) + sh->funcs->destroy(sh); + semanage_conf_destroy(sh->conf); + sepol_handle_destroy(sh->sepolh); + free(sh); +} + +hidden_def(semanage_handle_destroy) + +/********************* public transaction functions *********************/ +int semanage_begin_transaction(semanage_handle_t * sh) +{ + assert(sh != NULL && sh->funcs != NULL + && sh->funcs->begin_trans != NULL); + if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + if (sh->is_in_transaction) { + return 0; + } + + if (sh->funcs->begin_trans(sh) < 0) { + return -1; + } + sh->is_in_transaction = 1; + return 0; +} + +hidden_def(semanage_begin_transaction) + +int semanage_commit(semanage_handle_t * sh) +{ + int retval; + assert(sh != NULL && sh->funcs != NULL && sh->funcs->commit != NULL); + if (!sh->is_in_transaction) { + ERR(sh, + "Will not commit because caller does not have a transaction lock yet."); + return -1; + } + retval = sh->funcs->commit(sh); + sh->is_in_transaction = 0; + sh->modules_modified = 0; + return retval; +}
diff --git a/selinux/libsemanage/src/handle.h b/selinux/libsemanage/src/handle.h new file mode 100644 index 0000000..64175c4 --- /dev/null +++ b/selinux/libsemanage/src/handle.h
@@ -0,0 +1,229 @@ +/* Author: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Ivan Gyurdiev <ivg2@cornell.edu> + * + * Copyright (C) 2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_INTERNAL_HANDLE_H_ +#define _SEMANAGE_INTERNAL_HANDLE_H_ + +#include <stdint.h> +#include <stddef.h> +#include "handle_internal.h" +#include <sepol/handle.h> +#include "modules.h" +#include "semanage_conf.h" +#include "database.h" +#include "direct_api.h" +#include "policy.h" + +struct semanage_handle { + int con_id; /* Connection ID */ + + /* Error handling */ + int msg_level; + const char *msg_channel; + const char *msg_fname; +#ifdef __GNUC__ + __attribute__ ((format(printf, 3, 4))) +#endif + void (*msg_callback) (void *varg, + semanage_handle_t * handle, const char *fmt, ...); + void *msg_callback_arg; + + /* Direct vs Server specific handle */ + union { + struct semanage_direct_handle direct; + } u; + + /* Libsepol handle */ + sepol_handle_t *sepolh; + + semanage_conf_t *conf; + + uint16_t priority; + int is_connected; + int is_in_transaction; + int do_reload; /* whether to reload policy after commit */ + int do_rebuild; /* whether to rebuild policy if there were no changes */ + int modules_modified; + int create_store; /* whether to create the store if it does not exist + * this will only have an effect on direct connections */ + int do_check_contexts; /* whether to run setfiles check the file contexts file */ + + /* This timeout is used for transactions and waiting for lock + -1 means wait indefinetely + 0 means return immediately + >0 means wait that many seconds */ + int timeout; + + /* these function pointers will point to the appropriate + * routine given the connection type. think of these as + * simulating polymorphism for non-OO languages. */ + struct semanage_policy_table *funcs; + + /* Object databases */ +#define DBASE_COUNT 19 + +/* Local modifications */ +#define DBASE_LOCAL_USERS_BASE 0 +#define DBASE_LOCAL_USERS_EXTRA 1 +#define DBASE_LOCAL_USERS 2 +#define DBASE_LOCAL_PORTS 3 +#define DBASE_LOCAL_INTERFACES 4 +#define DBASE_LOCAL_BOOLEANS 5 +#define DBASE_LOCAL_FCONTEXTS 6 +#define DBASE_LOCAL_SEUSERS 7 +#define DBASE_LOCAL_NODES 8 + +/* Policy + Local modifications */ +#define DBASE_POLICY_USERS_BASE 9 +#define DBASE_POLICY_USERS_EXTRA 10 +#define DBASE_POLICY_USERS 11 +#define DBASE_POLICY_PORTS 12 +#define DBASE_POLICY_INTERFACES 13 +#define DBASE_POLICY_BOOLEANS 14 +#define DBASE_POLICY_FCONTEXTS 15 +#define DBASE_POLICY_SEUSERS 16 +#define DBASE_POLICY_NODES 17 + +/* Active kernel policy */ +#define DBASE_ACTIVE_BOOLEANS 18 + dbase_config_t dbase[DBASE_COUNT]; +}; + +/* === Local modifications === */ +static inline + dbase_config_t * semanage_user_base_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_USERS_BASE]; +} + +static inline + dbase_config_t * semanage_user_extra_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_USERS_EXTRA]; +} + +static inline + dbase_config_t * semanage_user_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_USERS]; +} + +static inline + dbase_config_t * semanage_port_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_PORTS]; +} + +static inline + dbase_config_t * semanage_iface_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_INTERFACES]; +} + +static inline + dbase_config_t * semanage_bool_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_BOOLEANS]; +} + +static inline + dbase_config_t * semanage_fcontext_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_FCONTEXTS]; +} + +static inline + dbase_config_t * semanage_seuser_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_SEUSERS]; +} + +static inline + dbase_config_t * semanage_node_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_NODES]; +} + +/* === Policy + Local modifications === */ +static inline + dbase_config_t * semanage_user_base_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_USERS_BASE]; +} + +static inline + dbase_config_t * semanage_user_extra_dbase_policy(semanage_handle_t * + handle) +{ + return &handle->dbase[DBASE_POLICY_USERS_EXTRA]; +} + +static inline + dbase_config_t * semanage_user_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_USERS]; +} + +static inline + dbase_config_t * semanage_port_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_PORTS]; +} + +static inline + dbase_config_t * semanage_iface_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_INTERFACES]; +} + +static inline + dbase_config_t * semanage_bool_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_BOOLEANS]; +} + +static inline + dbase_config_t * semanage_fcontext_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_FCONTEXTS]; +} + +static inline + dbase_config_t * semanage_seuser_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_SEUSERS]; +} + +static inline + dbase_config_t * semanage_node_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_NODES]; +} + +/* === Active kernel policy === */ +static inline + dbase_config_t * semanage_bool_dbase_active(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_ACTIVE_BOOLEANS]; +} + +#endif
diff --git a/selinux/libsemanage/src/handle_internal.h b/selinux/libsemanage/src/handle_internal.h new file mode 100644 index 0000000..66ce270 --- /dev/null +++ b/selinux/libsemanage/src/handle_internal.h
@@ -0,0 +1,12 @@ +#ifndef _SEMANAGE_HANDLE_INTERNAL_H_ +#define _SEMANAGE_HANDLE_INTERNAL_H_ + +#include <semanage/handle.h> +#include "dso.h" + +hidden_proto(semanage_begin_transaction) + hidden_proto(semanage_handle_destroy) + hidden_proto(semanage_reload_policy) + hidden_proto(semanage_access_check) + hidden_proto(semanage_set_root) +#endif
diff --git a/selinux/libsemanage/src/iface_internal.h b/selinux/libsemanage/src/iface_internal.h new file mode 100644 index 0000000..1f67836 --- /dev/null +++ b/selinux/libsemanage/src/iface_internal.h
@@ -0,0 +1,40 @@ +#ifndef _SEMANAGE_IFACE_INTERNAL_H_ +#define _SEMANAGE_IFACE_INTERNAL_H_ + +#include <semanage/iface_record.h> +#include <semanage/interfaces_local.h> +#include <semanage/interfaces_policy.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_iface_create) + hidden_proto(semanage_iface_compare) + hidden_proto(semanage_iface_compare2) + hidden_proto(semanage_iface_clone) + hidden_proto(semanage_iface_free) + hidden_proto(semanage_iface_get_ifcon) + hidden_proto(semanage_iface_get_msgcon) + hidden_proto(semanage_iface_get_name) + hidden_proto(semanage_iface_key_extract) + hidden_proto(semanage_iface_key_free) + hidden_proto(semanage_iface_set_ifcon) + hidden_proto(semanage_iface_set_msgcon) + hidden_proto(semanage_iface_set_name) + +/* IFACE RECORD: metod table */ +extern record_table_t SEMANAGE_IFACE_RTABLE; + +extern int iface_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void iface_policydb_dbase_release(dbase_config_t * dconfig); + +extern int iface_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void iface_file_dbase_release(dbase_config_t * dconfig); + +#endif
diff --git a/selinux/libsemanage/src/iface_record.c b/selinux/libsemanage/src/iface_record.c new file mode 100644 index 0000000..e7d72d7 --- /dev/null +++ b/selinux/libsemanage/src/iface_record.c
@@ -0,0 +1,169 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_iface_t (Network Interface) + * Object: semanage_iface_key_t (Network Interface Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/context_record.h> +#include <sepol/iface_record.h> + +typedef sepol_context_t semanage_context_t; +typedef sepol_iface_t semanage_iface_t; +typedef sepol_iface_key_t semanage_iface_key_t; +#define _SEMANAGE_CONTEXT_DEFINED_ +#define _SEMANAGE_IFACE_DEFINED_ + +typedef sepol_iface_t record_t; +typedef sepol_iface_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "iface_internal.h" +#include "handle.h" +#include "database.h" + +/* Key */ +int semanage_iface_compare(const semanage_iface_t * iface, + const semanage_iface_key_t * key) +{ + + return sepol_iface_compare(iface, key); +} + +hidden_def(semanage_iface_compare) + +int semanage_iface_compare2(const semanage_iface_t * iface, + const semanage_iface_t * iface2) +{ + + return sepol_iface_compare2(iface, iface2); +} + +hidden_def(semanage_iface_compare2) + +static int semanage_iface_compare2_qsort(const semanage_iface_t ** iface, + const semanage_iface_t ** iface2) +{ + + return sepol_iface_compare2(*iface, *iface2); +} + +int semanage_iface_key_create(semanage_handle_t * handle, + const char *name, semanage_iface_key_t ** key_ptr) +{ + + return sepol_iface_key_create(handle->sepolh, name, key_ptr); +} + +int semanage_iface_key_extract(semanage_handle_t * handle, + const semanage_iface_t * iface, + semanage_iface_key_t ** key_ptr) +{ + + return sepol_iface_key_extract(handle->sepolh, iface, key_ptr); +} + +hidden_def(semanage_iface_key_extract) + +void semanage_iface_key_free(semanage_iface_key_t * key) +{ + + sepol_iface_key_free(key); +} + +hidden_def(semanage_iface_key_free) + +/* Name */ +const char *semanage_iface_get_name(const semanage_iface_t * iface) +{ + + return sepol_iface_get_name(iface); +} + +hidden_def(semanage_iface_get_name) + +int semanage_iface_set_name(semanage_handle_t * handle, + semanage_iface_t * iface, const char *name) +{ + + return sepol_iface_set_name(handle->sepolh, iface, name); +} + +hidden_def(semanage_iface_set_name) + +/* Context */ +semanage_context_t *semanage_iface_get_ifcon(const semanage_iface_t * iface) +{ + + return sepol_iface_get_ifcon(iface); +} + +hidden_def(semanage_iface_get_ifcon) + +int semanage_iface_set_ifcon(semanage_handle_t * handle, + semanage_iface_t * iface, semanage_context_t * con) +{ + + return sepol_iface_set_ifcon(handle->sepolh, iface, con); +} + +hidden_def(semanage_iface_set_ifcon) + +semanage_context_t *semanage_iface_get_msgcon(const semanage_iface_t * iface) +{ + + return sepol_iface_get_msgcon(iface); +} + +hidden_def(semanage_iface_get_msgcon) + +int semanage_iface_set_msgcon(semanage_handle_t * handle, + semanage_iface_t * iface, + semanage_context_t * con) +{ + + return sepol_iface_set_msgcon(handle->sepolh, iface, con); +} + +hidden_def(semanage_iface_set_msgcon) + +/* Create/Clone/Destroy */ +int semanage_iface_create(semanage_handle_t * handle, + semanage_iface_t ** iface_ptr) +{ + + return sepol_iface_create(handle->sepolh, iface_ptr); +} + +hidden_def(semanage_iface_create) + +int semanage_iface_clone(semanage_handle_t * handle, + const semanage_iface_t * iface, + semanage_iface_t ** iface_ptr) +{ + + return sepol_iface_clone(handle->sepolh, iface, iface_ptr); +} + +hidden_def(semanage_iface_clone) + +void semanage_iface_free(semanage_iface_t * iface) +{ + + sepol_iface_free(iface); +} + +hidden_def(semanage_iface_free) + +/* Record base functions */ +record_table_t SEMANAGE_IFACE_RTABLE = { + .create = semanage_iface_create, + .key_extract = semanage_iface_key_extract, + .key_free = semanage_iface_key_free, + .clone = semanage_iface_clone, + .compare = semanage_iface_compare, + .compare2 = semanage_iface_compare2, + .compare2_qsort = semanage_iface_compare2_qsort, + .free = semanage_iface_free, +};
diff --git a/selinux/libsemanage/src/interfaces_file.c b/selinux/libsemanage/src/interfaces_file.c new file mode 100644 index 0000000..1478af9 --- /dev/null +++ b/selinux/libsemanage/src/interfaces_file.c
@@ -0,0 +1,175 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_iface; +struct semanage_iface_key; +typedef struct semanage_iface record_t; +typedef struct semanage_iface_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <semanage/handle.h> +#include "iface_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int iface_print(semanage_handle_t * handle, + semanage_iface_t * iface, FILE * str) +{ + + char *con_str = NULL; + + const char *name = semanage_iface_get_name(iface); + semanage_context_t *ifcon = semanage_iface_get_ifcon(iface); + semanage_context_t *msgcon = semanage_iface_get_msgcon(iface); + + if (fprintf(str, "netifcon %s ", name) < 0) + goto err; + + if (semanage_context_to_string(handle, ifcon, &con_str) < 0) + goto err; + if (fprintf(str, "%s ", con_str) < 0) + goto err; + free(con_str); + con_str = NULL; + + if (semanage_context_to_string(handle, msgcon, &con_str) < 0) + goto err; + if (fprintf(str, "%s\n", con_str) < 0) + goto err; + free(con_str); + con_str = NULL; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not print interface %s to stream", name); + free(con_str); + return STATUS_ERR; +} + +static int iface_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_iface_t * iface) +{ + + char *str = NULL; + semanage_context_t *con = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Header */ + if (parse_assert_str(handle, info, "netifcon") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Name */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_iface_set_name(handle, iface, str) < 0) + goto err; + free(str); + str = NULL; + + /* Interface context */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_context_from_string(handle, str, &con) < 0) { + ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s", + str, info->filename, info->lineno, info->orig_line); + goto err; + } + if (con == NULL) { + ERR(handle, "<<none>> context is not valid for " + "interfaces (%s: %u)\n%s", info->filename, + info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_iface_set_ifcon(handle, iface, con) < 0) + goto err; + semanage_context_free(con); + con = NULL; + + /* Message context */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_context_from_string(handle, str, &con) < 0) { + ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s", + str, info->filename, info->lineno, info->orig_line); + goto err; + } + if (con == NULL) { + ERR(handle, "<<none>> context is not valid for " + "interfaces (%s: %u)\n%s", info->filename, + info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_iface_set_msgcon(handle, iface, con) < 0) + goto err; + semanage_context_free(con); + con = NULL; + + if (parse_assert_space(handle, info) < 0) + goto err; + + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse interface record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* IFACE RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_IFACE_FILE_RTABLE = { + .parse = iface_parse, + .print = iface_print, +}; + +int iface_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_IFACE_RTABLE, + &SEMANAGE_IFACE_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void iface_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/interfaces_local.c b/selinux/libsemanage/src/interfaces_local.c new file mode 100644 index 0000000..acf6851 --- /dev/null +++ b/selinux/libsemanage/src/interfaces_local.c
@@ -0,0 +1,71 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_iface; +struct semanage_iface_key; +typedef struct semanage_iface_key record_key_t; +typedef struct semanage_iface record_t; +#define DBASE_RECORD_DEFINED + +#include "iface_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_iface_modify_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, + const semanage_iface_t * data) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_iface_del_local(semanage_handle_t * handle, + const semanage_iface_key_t * key) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_iface_query_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, + semanage_iface_t ** response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_iface_exists_local(semanage_handle_t * handle, + const semanage_iface_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_iface_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_iface_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_iface_t * + record, void *varg), + void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_iface_list_local(semanage_handle_t * handle, + semanage_iface_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/interfaces_policy.c b/selinux/libsemanage/src/interfaces_policy.c new file mode 100644 index 0000000..7f9b2ef --- /dev/null +++ b/selinux/libsemanage/src/interfaces_policy.c
@@ -0,0 +1,52 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_iface; +struct semanage_iface_key; +typedef struct semanage_iface_key record_key_t; +typedef struct semanage_iface record_t; +#define DBASE_RECORD_DEFINED + +#include "iface_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_iface_query(semanage_handle_t * handle, + const semanage_iface_key_t * key, + semanage_iface_t ** response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_iface_exists(semanage_handle_t * handle, + const semanage_iface_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_iface_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_iface_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_iface_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_iface_list(semanage_handle_t * handle, + semanage_iface_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_iface_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/interfaces_policydb.c b/selinux/libsemanage/src/interfaces_policydb.c new file mode 100644 index 0000000..552ce7d --- /dev/null +++ b/selinux/libsemanage/src/interfaces_policydb.c
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_iface; +struct semanage_iface_key; +typedef struct semanage_iface record_t; +typedef struct semanage_iface_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <sepol/interfaces.h> +#include <semanage/handle.h> +#include "iface_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* INTERFACE RECRORD (SEPOL): POLICYDB extension: method table */ +record_policydb_table_t SEMANAGE_IFACE_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t) sepol_iface_modify, + .set = NULL, + .query = (record_policydb_table_query_t) sepol_iface_query, + .count = (record_policydb_table_count_t) sepol_iface_count, + .exists = (record_policydb_table_exists_t) sepol_iface_exists, + .iterate = (record_policydb_table_iterate_t) sepol_iface_iterate, +}; + +int iface_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_policydb_init(handle, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + &SEMANAGE_IFACE_RTABLE, + &SEMANAGE_IFACE_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + return STATUS_SUCCESS; +} + +void iface_policydb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_policydb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/libsemanage.map b/selinux/libsemanage/src/libsemanage.map new file mode 100644 index 0000000..34b553d --- /dev/null +++ b/selinux/libsemanage/src/libsemanage.map
@@ -0,0 +1,64 @@ +LIBSEMANAGE_1.0 { + global: semanage_handle_create; semanage_handle_destroy; + semanage_is_managed; semanage_connect; semanage_disconnect; + semanage_msg_*; + semanage_begin_transaction; semanage_commit; + semanage_module_install; semanage_module_install_file; + semanage_module_upgrade; semanage_module_upgrade_file; + semanage_module_install_base; semanage_module_install_base_file; + semanage_module_enable; + semanage_module_disable; + semanage_module_remove; + semanage_module_list; semanage_module_info_datum_destroy; + semanage_module_list_nth; semanage_module_get_name; + semanage_module_get_version; semanage_select_store; + semanage_module_get_enabled; + semanage_reload_policy; semanage_set_reload; semanage_set_rebuild; + semanage_set_root; + semanage_root; + semanage_user_*; semanage_bool_*; semanage_seuser_*; + semanage_iface_*; semanage_port_*; semanage_context_*; + semanage_node_*; + semanage_fcontext_*; semanage_access_check; semanage_set_create_store; + semanage_is_connected; semanage_get_disable_dontaudit; semanage_set_disable_dontaudit; + semanage_mls_enabled; + semanage_set_check_contexts; + semanage_get_preserve_tunables; semanage_set_preserve_tunables; + local: *; +}; + +LIBSEMANAGE_1.1 { + global: + semanage_module_install; + semanage_module_extract; + semanage_get_hll_compiler_path; + semanage_get_ignore_module_cache; + semanage_set_ignore_module_cache; + semanage_get_default_priority; + semanage_set_default_priority; + semanage_module_info_create; + semanage_module_info_destroy; + semanage_module_info_get_priority; + semanage_module_info_get_name; + semanage_module_info_get_lang_ext; + semanage_module_info_get_enabled; + semanage_module_info_set_priority; + semanage_module_info_set_name; + semanage_module_info_set_lang_ext; + semanage_module_info_set_enabled; + semanage_module_key_create; + semanage_module_key_destroy; + semanage_module_key_get_priority; + semanage_module_key_get_name; + semanage_module_key_set_priority; + semanage_module_key_set_name; + semanage_module_get_module_info; + semanage_module_list_all; + semanage_module_get_enabled; + semanage_module_set_enabled; + semanage_module_install_info; + semanage_module_upgrade_info; + semanage_module_remove_key; + semanage_set_store_root; + local: *; +} LIBSEMANAGE_1.0;
diff --git a/selinux/libsemanage/src/libsemanage.pc.in b/selinux/libsemanage/src/libsemanage.pc.in new file mode 100644 index 0000000..81e1805 --- /dev/null +++ b/selinux/libsemanage/src/libsemanage.pc.in
@@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/@libdir@ +includedir=@includedir@ + +Name: libsemanage +Description: SELinux management library +Version: @VERSION@ +URL: http://userspace.selinuxproject.org/ +Requires.private: libselinux libsepol ustr +Libs: -L${libdir} -lsemanage +Libs.private: -lbz2 +Cflags: -I${includedir}
diff --git a/selinux/libsemanage/src/module_internal.h b/selinux/libsemanage/src/module_internal.h new file mode 100644 index 0000000..c99f6c2 --- /dev/null +++ b/selinux/libsemanage/src/module_internal.h
@@ -0,0 +1,27 @@ +#ifndef _SEMANAGE_MODULE_INTERNAL_H_ +#define _SEMANAGE_MODULE_INTERNAL_H_ + +#include <semanage/modules.h> +#include "dso.h" + +hidden_proto(semanage_module_get_name) + hidden_proto(semanage_module_info_datum_destroy) + hidden_proto(semanage_module_list_nth) + hidden_proto(semanage_module_info_create) + hidden_proto(semanage_module_info_destroy) + hidden_proto(semanage_module_info_get_priority) + hidden_proto(semanage_module_info_get_name) + hidden_proto(semanage_module_info_get_lang_ext) + hidden_proto(semanage_module_info_get_enabled) + hidden_proto(semanage_module_info_set_priority) + hidden_proto(semanage_module_info_set_name) + hidden_proto(semanage_module_info_set_lang_ext) + hidden_proto(semanage_module_info_set_enabled) + hidden_proto(semanage_module_key_create) + hidden_proto(semanage_module_key_destroy) + hidden_proto(semanage_module_key_get_priority) + hidden_proto(semanage_module_key_get_name) + hidden_proto(semanage_module_key_set_priority) + hidden_proto(semanage_module_key_set_name) + hidden_proto(semanage_module_set_enabled) +#endif
diff --git a/selinux/libsemanage/src/modules.c b/selinux/libsemanage/src/modules.c new file mode 100644 index 0000000..90c5e49 --- /dev/null +++ b/selinux/libsemanage/src/modules.c
@@ -0,0 +1,1146 @@ +/* Author: Joshua Brindle <jbrindle@tresys.co + * Jason Tang <jtang@tresys.com> + * Caleb Case <ccase@tresys.com> + * + * Copyright (C) 2004-2005,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 + */ + +/* This file implements only the publicly-visible module functions to libsemanage. */ + +#include "direct_api.h" +#include "semanage_conf.h" +#include "semanage_store.h" + +#include <stdarg.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <ctype.h> + +#include "handle.h" +#include "modules.h" +#include "debug.h" + +asm(".symver semanage_module_get_enabled_1_1,semanage_module_get_enabled@@LIBSEMANAGE_1.1"); +asm(".symver semanage_module_get_enabled_1_0,semanage_module_get_enabled@LIBSEMANAGE_1.0"); +asm(".symver semanage_module_install_pp,semanage_module_install@LIBSEMANAGE_1.0"); +asm(".symver semanage_module_install_hll,semanage_module_install@@LIBSEMANAGE_1.1"); + +/* Takes a module stored in 'module_data' and parses its headers. + * Sets reference variables 'module_name' to module's name and + * 'version' to module's version. The caller is responsible for + * free()ing 'module_name' and 'version'; they will be + * set to NULL upon entering this function. Returns 0 on success, -1 + * if out of memory, or -2 if data did not represent a module. + */ +static int parse_module_headers(semanage_handle_t * sh, char *module_data, + size_t data_len, char **module_name, char **version) +{ + struct sepol_policy_file *pf; + int file_type; + *version = NULL; + + if (sepol_policy_file_create(&pf)) { + ERR(sh, "Out of memory!"); + return -1; + } + sepol_policy_file_set_mem(pf, module_data, data_len); + sepol_policy_file_set_handle(pf, sh->sepolh); + if (module_data == NULL || + data_len == 0 || + sepol_module_package_info(pf, &file_type, module_name, version) == -1) { + sepol_policy_file_free(pf); + ERR(sh, "Could not parse module data."); + return -2; + } + sepol_policy_file_free(pf); + if (file_type != SEPOL_POLICY_MOD) { + ERR(sh, "Data did not represent a pp module. Please upgrade to the latest version of libsemanage to support hll modules."); + return -2; + } + + return 0; +} + +/* This function is used to preserve ABI compatibility with + * versions of semodule using LIBSEMANAGE_1.0 + */ +int semanage_module_install_pp(semanage_handle_t * sh, + char *module_data, size_t data_len) +{ + char *name = NULL; + char *version = NULL; + int status; + + if ((status = parse_module_headers(sh, module_data, data_len, &name, &version)) != 0) { + goto cleanup; + } + + status = semanage_module_install_hll(sh, module_data, data_len, name, "pp"); + +cleanup: + free(name); + free(version); + return status; +} + +int semanage_module_install_hll(semanage_handle_t * sh, + char *module_data, size_t data_len, const char *name, const char *ext_lang) +{ + if (sh->funcs->install == NULL) { + ERR(sh, + "No install function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->install(sh, module_data, data_len, name, ext_lang); +} + +int semanage_module_install_file(semanage_handle_t * sh, + const char *module_name) { + + if (sh->funcs->install_file == NULL) { + ERR(sh, + "No install function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->install_file(sh, module_name); +} + +int semanage_module_extract(semanage_handle_t * sh, + semanage_module_key_t *modkey, + int extract_cil, + void **mapped_data, + size_t *data_len, + semanage_module_info_t **modinfo) { + if (sh->funcs->extract == NULL) { + ERR(sh, + "No get function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + return sh->funcs->extract(sh, modkey, extract_cil, mapped_data, data_len, modinfo); +} + +/* Legacy function that remains to preserve ABI + * compatibility. Please use semanage_module_install instead. + */ +int semanage_module_upgrade(semanage_handle_t * sh, + char *module_data, size_t data_len) +{ + return semanage_module_install_pp(sh, module_data, data_len); + +} + +/* Legacy function that remains to preserve ABI + * compatibility. Please use semanage_module_install_file instead. + */ +int semanage_module_upgrade_file(semanage_handle_t * sh, + const char *module_name) +{ + return semanage_module_install_file(sh, module_name); +} + +/* Legacy function that remains to preserve ABI + * compatibility. Please use semanage_module_install instead. + */ +int semanage_module_install_base(semanage_handle_t * sh, + char *module_data, size_t data_len) +{ + return semanage_module_install_pp(sh, module_data, data_len); +} + +/* Legacy function that remains to preserve ABI + * compatibility. Please use semanage_module_install_file instead. + */ +int semanage_module_install_base_file(semanage_handle_t * sh, + const char *module_name) +{ + return semanage_module_install_file(sh, module_name); +} + +int semanage_module_remove(semanage_handle_t * sh, char *module_name) +{ + if (sh->funcs->remove == NULL) { + ERR(sh, "No remove function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->remove(sh, module_name); +} + +int semanage_module_list(semanage_handle_t * sh, + semanage_module_info_t ** modinfo, int *num_modules) +{ + if (sh->funcs->list == NULL) { + ERR(sh, "No list function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + return sh->funcs->list(sh, modinfo, num_modules); +} + +void semanage_module_info_datum_destroy(semanage_module_info_t * modinfo) +{ + if (modinfo != NULL) { + modinfo->priority = 0; + + free(modinfo->name); + modinfo->name = NULL; + + free(modinfo->lang_ext); + modinfo->lang_ext = NULL; + + modinfo->enabled = -1; + } +} + +hidden_def(semanage_module_info_datum_destroy) + +semanage_module_info_t *semanage_module_list_nth(semanage_module_info_t * list, + int n) +{ + return list + n; +} + +hidden_def(semanage_module_list_nth) + +const char *semanage_module_get_name(semanage_module_info_t * modinfo) +{ + return modinfo->name; +} + +hidden_def(semanage_module_get_name) + +/* Legacy function that remains to preserve ABI + * compatibility. + */ +const char *semanage_module_get_version(semanage_module_info_t * modinfo + __attribute__ ((unused))) +{ + return ""; +} + +int semanage_module_info_create(semanage_handle_t *sh, + semanage_module_info_t **modinfo) +{ + assert(sh); + assert(modinfo); + + *modinfo = malloc(sizeof(semanage_module_info_t)); + if (*modinfo == NULL) return -1; + + return semanage_module_info_init(sh, *modinfo); +} + +hidden_def(semanage_module_info_create) + +int semanage_module_info_destroy(semanage_handle_t *sh, + semanage_module_info_t *modinfo) +{ + assert(sh); + + if (!modinfo) { + return 0; + } + + free(modinfo->name); + free(modinfo->lang_ext); + + return semanage_module_info_init(sh, modinfo); +} + +hidden_def(semanage_module_info_destroy) + +int semanage_module_info_init(semanage_handle_t *sh, + semanage_module_info_t *modinfo) +{ + assert(sh); + assert(modinfo); + + modinfo->priority = 0; + modinfo->name = NULL; + modinfo->lang_ext = NULL; + modinfo->enabled = -1; + + return 0; +} + +int semanage_module_info_clone(semanage_handle_t *sh, + const semanage_module_info_t *source, + semanage_module_info_t *target) +{ + assert(sh); + assert(source); + assert(target); + + int status = 0; + int ret = 0; + + ret = semanage_module_info_destroy(sh, target); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_priority(sh, target, source->priority); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_name(sh, target, source->name); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_lang_ext(sh, target, source->lang_ext); + if (ret != 0) { + status = -1; + goto cleanup; + } + + ret = semanage_module_info_set_enabled(sh, target, source->enabled); + if (ret != 0) { + status = -1; + goto cleanup; + } + +cleanup: + if (status != 0) semanage_module_info_destroy(sh, target); + return status; +} + +int semanage_module_info_get_priority(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + uint16_t *priority) +{ + assert(sh); + assert(modinfo); + assert(priority); + + *priority = modinfo->priority; + + return 0; +} + +hidden_def(semanage_module_info_get_priority) + +int semanage_module_info_get_name(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char **name) +{ + assert(sh); + assert(modinfo); + assert(name); + + *name = modinfo->name; + + return 0; +} + +hidden_def(semanage_module_info_get_name) + +int semanage_module_info_get_lang_ext(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char **lang_ext) +{ + assert(sh); + assert(modinfo); + assert(lang_ext); + + *lang_ext = modinfo->lang_ext; + + return 0; +} + +hidden_def(semanage_module_info_get_lang_ext) + +int semanage_module_info_get_enabled(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + int *enabled) +{ + assert(sh); + assert(modinfo); + assert(enabled); + + *enabled = modinfo->enabled; + + return 0; +} + +hidden_def(semanage_module_info_get_enabled) + +int semanage_module_info_set_priority(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + uint16_t priority) +{ + assert(sh); + assert(modinfo); + + /* Verify priority */ + if (semanage_module_validate_priority(priority) < 0) { + errno = 0; + ERR(sh, "Priority %d is invalid.", priority); + return -1; + } + + modinfo->priority = priority; + + return 0; +} + +hidden_def(semanage_module_info_set_priority) + +int semanage_module_info_set_name(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char *name) +{ + assert(sh); + assert(modinfo); + assert(name); + + char * tmp; + + /* Verify name */ + if (semanage_module_validate_name(name) < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", name); + return -1; + } + + tmp = strdup(name); + if (!tmp) { + ERR(sh, "No memory available for strdup"); + return -1; + } + + free(modinfo->name); + modinfo->name = tmp; + + return 0; +} + +hidden_def(semanage_module_info_set_name) + +int semanage_module_info_set_lang_ext(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + const char *lang_ext) +{ + assert(sh); + assert(modinfo); + assert(lang_ext); + + char * tmp; + + /* Verify extension */ + if (semanage_module_validate_lang_ext(lang_ext) < 0) { + errno = 0; + ERR(sh, "Language extensions %s is invalid.", lang_ext); + return -1; + } + + tmp = strdup(lang_ext); + if (!tmp) { + ERR(sh, "No memory available for strdup"); + return -1; + } + + free(modinfo->lang_ext); + modinfo->lang_ext = tmp; + + return 0; +} + +hidden_def(semanage_module_info_set_lang_ext) + +int semanage_module_info_set_enabled(semanage_handle_t *sh, + semanage_module_info_t *modinfo, + int enabled) +{ + assert(sh); + assert(modinfo); + + /* Verify enabled */ + if (semanage_module_validate_enabled(enabled) < 0) { + errno = 0; + ERR(sh, "Enabled status %d is invalid.", enabled); + return -1; + } + + modinfo->enabled = enabled; + + return 0; +} + +hidden_def(semanage_module_info_set_enabled) + +int semanage_module_get_path(semanage_handle_t *sh, + const semanage_module_info_t *modinfo, + enum semanage_module_path_type type, + char *path, + size_t len) +{ + assert(sh); + assert(modinfo); + assert(path); + + int status = 0; + int ret = 0; + + const char *modules_path = NULL; + const char *file = NULL; + + modules_path = sh->is_in_transaction ? + semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES): + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); + + switch (type) { + case SEMANAGE_MODULE_PATH_PRIORITY: + /* verify priority */ + ret = semanage_module_validate_priority(modinfo->priority); + if (ret < 0) { + errno = 0; + ERR(sh, + "Priority %d is invalid.", + modinfo->priority); + status = ret; + goto cleanup; + } + + ret = snprintf(path, + len, + "%s/%03u", + modules_path, + modinfo->priority); + if (ret < 0 || (size_t)ret >= len) { + ERR(sh, "Unable to compose priority path."); + status = -1; + goto cleanup; + } + break; + case SEMANAGE_MODULE_PATH_NAME: + /* verify priority and name */ + ret = semanage_module_validate_priority(modinfo->priority); + if (ret < 0) { + errno = 0; + ERR(sh, + "Priority %d is invalid.", + modinfo->priority); + status = -1; + goto cleanup; + } + + ret = semanage_module_validate_name(modinfo->name); + if (ret < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modinfo->name); + status = -1; + goto cleanup; + } + + ret = snprintf(path, + len, + "%s/%03u/%s", + modules_path, + modinfo->priority, + modinfo->name); + if (ret < 0 || (size_t)ret >= len) { + ERR(sh, "Unable to compose name path."); + status = -1; + goto cleanup; + } + break; + case SEMANAGE_MODULE_PATH_HLL: + if (file == NULL) file = "hll"; + case SEMANAGE_MODULE_PATH_CIL: + if (file == NULL) file = "cil"; + case SEMANAGE_MODULE_PATH_LANG_EXT: + if (file == NULL) file = "lang_ext"; + + /* verify priority and name */ + ret = semanage_module_validate_priority(modinfo->priority); + if (ret < 0) { + errno = 0; + ERR(sh, + "Priority %d is invalid.", + modinfo->priority); + status = -1; + goto cleanup; + } + + ret = semanage_module_validate_name(modinfo->name); + if (ret < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modinfo->name); + status = -1; + goto cleanup; + } + + ret = snprintf(path, + len, + "%s/%03u/%s/%s", + modules_path, + modinfo->priority, + modinfo->name, + file); + if (ret < 0 || (size_t)ret >= len) { + ERR(sh, + "Unable to compose path for %s file.", + file); + status = -1; + goto cleanup; + } + break; + case SEMANAGE_MODULE_PATH_DISABLED: + /* verify name */ + ret = semanage_module_validate_name(modinfo->name); + if (ret < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", modinfo->name); + status = -1; + goto cleanup; + } + + ret = snprintf(path, + len, + "%s/disabled/%s", + modules_path, + modinfo->name); + if (ret < 0 || (size_t)ret >= len) { + ERR(sh, + "Unable to compose disabled status path."); + status = -1; + goto cleanup; + } + break; + default: + ERR(sh, "Invalid module path type %d.", type); + status = -1; + goto cleanup; + } + +cleanup: + return status; +} + +int semanage_module_key_create(semanage_handle_t *sh, + semanage_module_key_t **modkey) +{ + assert(sh); + assert(modkey); + + *modkey = malloc(sizeof(semanage_module_key_t)); + if (*modkey == NULL) return -1; + + return semanage_module_key_init(sh, *modkey); +} + +hidden_def(semanage_module_key_create) + +int semanage_module_key_destroy(semanage_handle_t *sh, + semanage_module_key_t *modkey) +{ + assert(sh); + + if (!modkey) { + return 0; + } + + free(modkey->name); + + return semanage_module_key_init(sh, modkey); +} + +hidden_def(semanage_module_key_destroy) + +int semanage_module_key_init(semanage_handle_t *sh, + semanage_module_key_t *modkey) +{ + assert(sh); + assert(modkey); + + modkey->name = NULL; + modkey->priority = 0; + + return 0; +} + +int semanage_module_key_get_name(semanage_handle_t *sh, + semanage_module_key_t *modkey, + const char **name) +{ + assert(sh); + assert(modkey); + assert(name); + + *name = modkey->name; + + return 0; +} + +hidden_def(semanage_module_key_get_name) + +int semanage_module_key_get_priority(semanage_handle_t *sh, + semanage_module_key_t *modkey, + uint16_t *priority) +{ + assert(sh); + assert(modkey); + assert(priority); + + *priority = modkey->priority; + + return 0; +} + +hidden_def(semanage_module_key_get_priority) + +int semanage_module_key_set_name(semanage_handle_t *sh, + semanage_module_key_t *modkey, + const char *name) +{ + assert(sh); + assert(modkey); + assert(name); + + int status = 0; + char *tmp = NULL; + + if (semanage_module_validate_name(name) < 0) { + errno = 0; + ERR(sh, "Name %s is invalid.", name); + return -1; + } + + tmp = strdup(name); + if (tmp == NULL) { + ERR(sh, "No memory available for strdup"); + status = -1; + goto cleanup; + } + + free(modkey->name); + modkey->name = tmp; + +cleanup: + return status; +} + +hidden_def(semanage_module_key_set_name) + +int semanage_module_key_set_priority(semanage_handle_t *sh, + semanage_module_key_t *modkey, + uint16_t priority) +{ + assert(sh); + assert(modkey); + + if (semanage_module_validate_priority(priority) < 0) { + errno = 0; + ERR(sh, "Priority %d is invalid.", priority); + return -1; + } + + modkey->priority = priority; + + return 0; +} + +hidden_def(semanage_module_key_set_priority) + +int semanage_module_get_enabled_1_1(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int *enabled) +{ + assert(sh); + assert(modkey); + assert(enabled); + + if (sh->funcs->get_enabled == NULL) { + ERR(sh, + "No get_enabled function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + + return sh->funcs->get_enabled(sh, modkey, enabled); +} + +int semanage_module_get_enabled_1_0(semanage_module_info_t *modinfo) +{ + return modinfo->enabled; +} + +int semanage_module_set_enabled(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + int enabled) +{ + assert(sh); + assert(modkey); + + if (sh->funcs->set_enabled == NULL) { + ERR(sh, + "No set_enabled function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + + sh->modules_modified = 1; + return sh->funcs->set_enabled(sh, modkey, enabled); +} + +hidden_def(semanage_module_set_enabled) + +/* This function exists only for ABI compatability. It has been deprecated and + * should not be used. Instead, use semanage_module_set_enabled() */ +int semanage_module_enable(semanage_handle_t *sh, char *module_name) +{ + int rc = -1; + semanage_module_key_t *modkey = NULL; + + rc = semanage_module_key_create(sh, &modkey); + if (rc != 0) + goto exit; + + rc = semanage_module_key_set_name(sh, modkey, module_name); + if (rc != 0) + goto exit; + + rc = semanage_module_set_enabled(sh, modkey, 1); + if (rc != 0) + goto exit; + + rc = 0; + +exit: + semanage_module_key_destroy(sh, modkey); + free(modkey); + + return rc; +} + +/* This function exists only for ABI compatability. It has been deprecated and + * should not be used. Instead, use semanage_module_set_enabled() */ +int semanage_module_disable(semanage_handle_t *sh, char *module_name) +{ + int rc = -1; + semanage_module_key_t *modkey = NULL; + + rc = semanage_module_key_create(sh, &modkey); + if (rc != 0) + goto exit; + + rc = semanage_module_key_set_name(sh, modkey, module_name); + if (rc != 0) + goto exit; + + rc = semanage_module_set_enabled(sh, modkey, 0); + if (rc != 0) + goto exit; + + rc = 0; + +exit: + semanage_module_key_destroy(sh, modkey); + free(modkey); + + return rc; +} + +/* Converts a string to a priority + * + * returns -1 if str is not a valid priority. + * returns 0 and sets priority if str is a valid priority + */ +int semanage_string_to_priority(const char *str, uint16_t *priority) +{ + unsigned long val; + char *endptr = NULL; + int status = -1; + + if (str == NULL || priority == NULL) { + goto exit; + } + + errno = 0; + + val = strtoul(str, &endptr, 10); + + if (errno != 0 || endptr == str || *endptr != '\0' || val > UINT16_MAX) { + goto exit; + } + + if (semanage_module_validate_priority((uint16_t)val) < 0) { + goto exit; + } + + *priority = val; + status = 0; + +exit: + return status; +} + +/* Validates a module info struct. + * + * Returns -1 if module is invalid, 0 otherwise. + */ +int semanage_module_info_validate(const semanage_module_info_t *modinfo) +{ + if (semanage_module_validate_priority(modinfo->priority) != 0 || + semanage_module_validate_name(modinfo->name) != 0 || + semanage_module_validate_lang_ext(modinfo->lang_ext) != 0 || + semanage_module_validate_enabled(modinfo->enabled) != 0) { + return -1; + } + return 0; +} + +#define PRIORITY_MIN 1 +#define PRIORITY_MAX 999 + +/* Validates priority. + * + * returns -1 if priority is not in the valid range, returns 0 otherwise + */ +int semanage_module_validate_priority(uint16_t priority) +{ + if (priority >= PRIORITY_MIN && priority <= PRIORITY_MAX) { + return 0; + } + + return -1; +} + +/* Validates module name. + * + * A module name must match one of the following regular expressions + * to be considered valid: + * + * ^[a-zA-Z](\.?[a-zA-Z0-9_-])*$ + * + * returns -1 if name is not valid, returns 0 otherwise + */ +int semanage_module_validate_name(const char * name) +{ + int status = 0; + + if (name == NULL) { + status = -1; + goto exit; + } + + if (!isalpha(*name)) { + status = -1; + goto exit; + } + +#define ISVALIDCHAR(c) (isalnum(c) || c == '_' || c == '-') + + for (name++; *name; name++) { + if (ISVALIDCHAR(*name)) { + continue; + } + if (*name == '.' && name++ && ISVALIDCHAR(*name)) { + continue; + } + status = -1; + goto exit; + } + +#undef ISVALIDCHAR + +exit: + return status; +} + +/* Validates module enabled status. + * + * Valid enabled values are 1, 0, and -1. + * + * returns 0 if enabled is a valid value, returns -1 otherwise. + */ +int semanage_module_validate_enabled(int enabled) +{ + if (enabled == 1 || enabled == 0 || enabled == -1) { + return 0; + } + + return -1; +} + +/* Validate extension. + * + * An extension must match the following regular expression to be + * considered valid: + * + * ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ + * + * returns 0 if ext is a valid value, returns -1 otherwise. + */ +int semanage_module_validate_lang_ext(const char *ext) +{ + int status = 0; + + if (ext == NULL) { + status = -1; + goto exit; + } + + if (!isalnum(*ext)) { + status = -1; + goto exit; + } + +#define ISVALIDCHAR(c) (isalnum(c) || c == '_' || c == '-') + + for (ext++; *ext; ext++) { + if (ISVALIDCHAR(*ext)) { + continue; + } + status = -1; + goto exit; + } + +#undef ISVALIDCHAR + +exit: + return status; +} + +int semanage_module_get_module_info(semanage_handle_t *sh, + const semanage_module_key_t *modkey, + semanage_module_info_t **modinfo) +{ + assert(sh); + assert(modkey); + assert(modinfo); + + if (sh->funcs->get_module_info == NULL) { + ERR(sh, + "No get module info function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + + return sh->funcs->get_module_info(sh, modkey, modinfo); +} + +int semanage_module_list_all(semanage_handle_t *sh, + semanage_module_info_t **modinfos, + int *modinfos_len) +{ + assert(sh); + assert(modinfos); + assert(modinfos_len); + + if (sh->funcs->list_all == NULL) { + ERR(sh, + "No list all function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } + + return sh->funcs->list_all(sh, modinfos, modinfos_len); +} + +int semanage_module_install_info(semanage_handle_t *sh, + const semanage_module_info_t *modinfo, + char *data, + size_t data_len) +{ + if (sh->funcs->install_info == NULL) { + ERR(sh, + "No install info function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->install_info(sh, modinfo, data, data_len); +} + +int semanage_module_remove_key(semanage_handle_t *sh, + const semanage_module_key_t *modkey) +{ + if (sh->funcs->remove_key== NULL) { + ERR(sh, + "No remove key function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->remove_key(sh, modkey); +} +
diff --git a/selinux/libsemanage/src/modules.h b/selinux/libsemanage/src/modules.h new file mode 100644 index 0000000..8a5c01f --- /dev/null +++ b/selinux/libsemanage/src/modules.h
@@ -0,0 +1,112 @@ +/* Author: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Caleb Case <ccase@tresys.com> + * + * Copyright (C) 2005,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 _SEMANAGE_INTERNAL_MODULES_H_ +#define _SEMANAGE_INTERNAL_MODULES_H_ + +#include <stdint.h> + +#include "module_internal.h" + +int semanage_module_install_pp(semanage_handle_t * sh, + char *module_data, size_t data_len); +int semanage_module_install_hll(semanage_handle_t * sh, + char *module_data, size_t data_len, const char *name, const char *ext_lang); +int semanage_module_upgrade(semanage_handle_t * sh, + char *module_data, size_t data_len); +int semanage_module_upgrade_file(semanage_handle_t * sh, + const char *module_name); +int semanage_module_install_base(semanage_handle_t * sh, + char *module_data, size_t data_len); +int semanage_module_install_base_file(semanage_handle_t * sh, + const char *module_name); + +/* Module Info */ +struct semanage_module_info { + uint16_t priority; /* key, module priority */ + char *name; /* key, module name */ + char *lang_ext; /* module source language extension */ + int enabled; /* module enabled/disabled status */ +}; + +/* Initializes a pre-allocated module info struct. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_init(semanage_handle_t *sh, + semanage_module_info_t *modinfo); + +/* Clones module info @source's members into module info @target. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_info_clone(semanage_handle_t *sh, + const semanage_module_info_t *source, + semanage_module_info_t *target); + +/* Convert a cstring to a priority. + * + * Returns 0 on success and -1 on error. + */ +int semanage_string_to_priority(const char *str, uint16_t *priority); + +int semanage_module_info_validate(const semanage_module_info_t *modinfo); +int semanage_module_validate_priority(uint16_t priority); +int semanage_module_validate_name(const char *name); +int semanage_module_validate_enabled(int enabled); +int semanage_module_validate_lang_ext(const char *ext); +int semanage_module_validate_version(const char *version); + +/* Module Key */ +struct semanage_module_key { + uint16_t priority; /* module priority */ + char *name; /* module name */ +}; + +/* Initializes a pre-allocated module key struct. + * + * Returns 0 on success, and -1 on error. + */ +int semanage_module_key_init(semanage_handle_t *sh, + semanage_module_key_t *modkey); + +/* Module Paths */ + +enum semanage_module_path_type { + SEMANAGE_MODULE_PATH_PRIORITY, + SEMANAGE_MODULE_PATH_NAME, + SEMANAGE_MODULE_PATH_HLL, + SEMANAGE_MODULE_PATH_CIL, + SEMANAGE_MODULE_PATH_LANG_EXT, + SEMANAGE_MODULE_PATH_DISABLED, +}; + +/* Get the module path for the given path @type. + * + * Returns 0 on success and -1 on error. + */ +int semanage_module_get_path(semanage_handle_t *sh, + const semanage_module_info_t *module, + enum semanage_module_path_type type, + char *path, + size_t len); + +#endif
diff --git a/selinux/libsemanage/src/node_internal.h b/selinux/libsemanage/src/node_internal.h new file mode 100644 index 0000000..5817560 --- /dev/null +++ b/selinux/libsemanage/src/node_internal.h
@@ -0,0 +1,55 @@ +#ifndef _SEMANAGE_NODE_INTERNAL_H_ +#define _SEMANAGE_NODE_INTERNAL_H_ + +#include <semanage/node_record.h> +#include <semanage/nodes_local.h> +#include <semanage/nodes_policy.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_node_create) + hidden_proto(semanage_node_compare) + hidden_proto(semanage_node_compare2) + hidden_proto(semanage_node_clone) + hidden_proto(semanage_node_free) + hidden_proto(semanage_node_key_extract) + hidden_proto(semanage_node_key_free) + hidden_proto(semanage_node_get_addr) + hidden_proto(semanage_node_get_addr_bytes) + hidden_proto(semanage_node_get_mask) + hidden_proto(semanage_node_get_mask_bytes) + hidden_proto(semanage_node_get_proto) + hidden_proto(semanage_node_set_addr) + hidden_proto(semanage_node_set_addr_bytes) + hidden_proto(semanage_node_set_mask) + hidden_proto(semanage_node_set_mask_bytes) + hidden_proto(semanage_node_set_proto) + hidden_proto(semanage_node_get_proto_str) + hidden_proto(semanage_node_get_con) + hidden_proto(semanage_node_set_con) + hidden_proto(semanage_node_list_local) + +/* NODE RECORD: method table */ +extern record_table_t SEMANAGE_NODE_RTABLE; + +extern int node_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void node_file_dbase_release(dbase_config_t * dconfig); + +extern int node_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void node_policydb_dbase_release(dbase_config_t * dconfig); + +extern int hidden semanage_node_validate_local(semanage_handle_t * handle); + +/* ==== Internal (to nodes) API === */ + +hidden int semanage_node_compare2_qsort(const semanage_node_t ** node, + const semanage_node_t ** node2); + +#endif
diff --git a/selinux/libsemanage/src/node_record.c b/selinux/libsemanage/src/node_record.c new file mode 100644 index 0000000..5368cee --- /dev/null +++ b/selinux/libsemanage/src/node_record.c
@@ -0,0 +1,240 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_node_t (Network Port) + * Object: semanage_node_key_t (Network Port Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/context_record.h> +#include <sepol/node_record.h> +#include <stddef.h> + +typedef sepol_context_t semanage_context_t; +typedef sepol_node_t semanage_node_t; +typedef sepol_node_key_t semanage_node_key_t; +#define _SEMANAGE_NODE_DEFINED_ +#define _SEMANAGE_CONTEXT_DEFINED_ + +typedef semanage_node_t record_t; +typedef semanage_node_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "node_internal.h" +#include "handle.h" +#include "database.h" + +/* Key */ +int semanage_node_compare(const semanage_node_t * node, + const semanage_node_key_t * key) +{ + + return sepol_node_compare(node, key); +} + +hidden_def(semanage_node_compare) + +int semanage_node_compare2(const semanage_node_t * node, + const semanage_node_t * node2) +{ + + return sepol_node_compare2(node, node2); +} + +hidden_def(semanage_node_compare2) + +hidden int semanage_node_compare2_qsort(const semanage_node_t ** node, + const semanage_node_t ** node2) +{ + + return sepol_node_compare2(*node, *node2); +} + +int semanage_node_key_create(semanage_handle_t * handle, + const char *addr, + const char *mask, + int proto, semanage_node_key_t ** key_ptr) +{ + + return sepol_node_key_create(handle->sepolh, addr, mask, proto, + key_ptr); +} + +int semanage_node_key_extract(semanage_handle_t * handle, + const semanage_node_t * node, + semanage_node_key_t ** key_ptr) +{ + + return sepol_node_key_extract(handle->sepolh, node, key_ptr); +} + +hidden_def(semanage_node_key_extract) + +void semanage_node_key_free(semanage_node_key_t * key) +{ + + sepol_node_key_free(key); +} + +hidden_def(semanage_node_key_free) + +/* Address */ +int semanage_node_get_addr(semanage_handle_t * handle, + const semanage_node_t * node, char **addr_ptr) +{ + + return sepol_node_get_addr(handle->sepolh, node, addr_ptr); +} + +hidden_def(semanage_node_get_addr) + +int semanage_node_get_addr_bytes(semanage_handle_t * handle, + const semanage_node_t * node, + char **addr, size_t * addr_sz) +{ + + return sepol_node_get_addr_bytes(handle->sepolh, node, addr, addr_sz); +} + +hidden_def(semanage_node_get_addr_bytes) + +int semanage_node_set_addr(semanage_handle_t * handle, + semanage_node_t * node, int proto, const char *addr) +{ + + return sepol_node_set_addr(handle->sepolh, node, proto, addr); +} + +hidden_def(semanage_node_set_addr) + +int semanage_node_set_addr_bytes(semanage_handle_t * handle, + semanage_node_t * node, + const char *addr, size_t addr_sz) +{ + + return sepol_node_set_addr_bytes(handle->sepolh, node, addr, addr_sz); +} + +hidden_def(semanage_node_set_addr_bytes) + +/* Netmask */ +int semanage_node_get_mask(semanage_handle_t * handle, + const semanage_node_t * node, char **mask_ptr) +{ + + return sepol_node_get_mask(handle->sepolh, node, mask_ptr); +} + +hidden_def(semanage_node_get_mask) + +int semanage_node_get_mask_bytes(semanage_handle_t * handle, + const semanage_node_t * node, + char **mask, size_t * mask_sz) +{ + + return sepol_node_get_mask_bytes(handle->sepolh, node, mask, mask_sz); +} + +hidden_def(semanage_node_get_mask_bytes) + +int semanage_node_set_mask(semanage_handle_t * handle, + semanage_node_t * node, int proto, const char *mask) +{ + + return sepol_node_set_mask(handle->sepolh, node, proto, mask); +} + +hidden_def(semanage_node_set_mask) + +int semanage_node_set_mask_bytes(semanage_handle_t * handle, + semanage_node_t * node, + const char *mask, size_t mask_sz) +{ + + return sepol_node_set_mask_bytes(handle->sepolh, node, mask, mask_sz); +} + +hidden_def(semanage_node_set_mask_bytes) + +/* Protocol */ +int semanage_node_get_proto(const semanage_node_t * node) +{ + + return sepol_node_get_proto(node); +} + +hidden_def(semanage_node_get_proto) + +void semanage_node_set_proto(semanage_node_t * node, int proto) +{ + + sepol_node_set_proto(node, proto); +} + +hidden_def(semanage_node_set_proto) + +const char *semanage_node_get_proto_str(int proto) +{ + + return sepol_node_get_proto_str(proto); +} + +hidden_def(semanage_node_get_proto_str) + +/* Context */ +semanage_context_t *semanage_node_get_con(const semanage_node_t * node) +{ + + return sepol_node_get_con(node); +} + +hidden_def(semanage_node_get_con) + +int semanage_node_set_con(semanage_handle_t * handle, + semanage_node_t * node, semanage_context_t * con) +{ + + return sepol_node_set_con(handle->sepolh, node, con); +} + +hidden_def(semanage_node_set_con) + +/* Create/Clone/Destroy */ +int semanage_node_create(semanage_handle_t * handle, + semanage_node_t ** node_ptr) +{ + + return sepol_node_create(handle->sepolh, node_ptr); +} + +hidden_def(semanage_node_create) + +int semanage_node_clone(semanage_handle_t * handle, + const semanage_node_t * node, + semanage_node_t ** node_ptr) +{ + + return sepol_node_clone(handle->sepolh, node, node_ptr); +} + +hidden_def(semanage_node_clone) + +void semanage_node_free(semanage_node_t * node) +{ + + sepol_node_free(node); +} + +hidden_def(semanage_node_free) + +/* Port base functions */ +record_table_t SEMANAGE_NODE_RTABLE = { + .create = semanage_node_create, + .key_extract = semanage_node_key_extract, + .key_free = semanage_node_key_free, + .clone = semanage_node_clone, + .compare = semanage_node_compare, + .compare2 = semanage_node_compare2, + .compare2_qsort = semanage_node_compare2_qsort, + .free = semanage_node_free, +};
diff --git a/selinux/libsemanage/src/nodes_file.c b/selinux/libsemanage/src/nodes_file.c new file mode 100644 index 0000000..f6c8895 --- /dev/null +++ b/selinux/libsemanage/src/nodes_file.c
@@ -0,0 +1,184 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_node; +struct semanage_node_key; +typedef struct semanage_node record_t; +typedef struct semanage_node_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <semanage/handle.h> +#include "node_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int node_print(semanage_handle_t * handle, + semanage_node_t * node, FILE * str) +{ + + char *con_str = NULL; + char *addr = NULL; + char *mask = NULL; + + int proto = semanage_node_get_proto(node); + const char *proto_str = semanage_node_get_proto_str(proto); + semanage_context_t *con = semanage_node_get_con(node); + + if (semanage_node_get_addr(handle, node, &addr) < 0) + goto err; + + if (semanage_node_get_mask(handle, node, &mask) < 0) + goto err; + + if (semanage_context_to_string(handle, con, &con_str) < 0) + goto err; + + if (fprintf + (str, "nodecon %s %s %s %s\n", proto_str, addr, mask, con_str) < 0) + goto err; + + free(addr); + free(mask); + free(con_str); + return STATUS_SUCCESS; + + err: + free(addr); + free(mask); + free(con_str); + ERR(handle, "could not print node to stream"); + return STATUS_ERR; +} + +static int node_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_node_t * node) +{ + + int proto; + char *str = NULL; + semanage_context_t *con = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Header */ + if (parse_assert_str(handle, info, "nodecon") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Protocol */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (!strcasecmp(str, "ipv4")) + proto = SEMANAGE_PROTO_IP4; + else if (!strcasecmp(str, "ipv6")) + proto = SEMANAGE_PROTO_IP6; + else { + ERR(handle, "invalid protocol \"%s\" (%s: %u):\n%s", str, + info->filename, info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + semanage_node_set_proto(node, proto); + + /* Address */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_node_set_addr(handle, node, proto, str) < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + free(str); + str = NULL; + + /* Netmask */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_node_set_mask(handle, node, proto, str) < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + free(str); + str = NULL; + + /* Port context */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_context_from_string(handle, str, &con) < 0) { + ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s", + str, info->filename, info->lineno, info->orig_line); + goto err; + } + if (con == NULL) { + ERR(handle, "<<none>> context is not valid " + "for nodes (%s: %u):\n%s", info->filename, + info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_node_set_con(handle, node, con) < 0) + goto err; + + if (parse_assert_space(handle, info) < 0) + goto err; + + semanage_context_free(con); + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse node record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* NODE RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_NODE_FILE_RTABLE = { + .parse = node_parse, + .print = node_print, +}; + +int node_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_NODE_RTABLE, + &SEMANAGE_NODE_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void node_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/nodes_local.c b/selinux/libsemanage/src/nodes_local.c new file mode 100644 index 0000000..93af450 --- /dev/null +++ b/selinux/libsemanage/src/nodes_local.c
@@ -0,0 +1,72 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_node; +struct semanage_node_key; +typedef struct semanage_node_key record_key_t; +typedef struct semanage_node record_t; +#define DBASE_RECORD_DEFINED + +#include "node_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_node_modify_local(semanage_handle_t * handle, + const semanage_node_key_t * key, + const semanage_node_t * data) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_node_del_local(semanage_handle_t * handle, + const semanage_node_key_t * key) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_node_query_local(semanage_handle_t * handle, + const semanage_node_key_t * key, + semanage_node_t ** response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_node_exists_local(semanage_handle_t * handle, + const semanage_node_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_node_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_node_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_node_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_node_list_local(semanage_handle_t * handle, + semanage_node_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_node_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +} + +hidden_def(semanage_node_list_local)
diff --git a/selinux/libsemanage/src/nodes_policy.c b/selinux/libsemanage/src/nodes_policy.c new file mode 100644 index 0000000..dc71cc8 --- /dev/null +++ b/selinux/libsemanage/src/nodes_policy.c
@@ -0,0 +1,52 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_node; +struct semanage_node_key; +typedef struct semanage_node_key record_key_t; +typedef struct semanage_node record_t; +#define DBASE_RECORD_DEFINED + +#include "node_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_node_query(semanage_handle_t * handle, + const semanage_node_key_t * key, + semanage_node_t ** response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_node_exists(semanage_handle_t * handle, + const semanage_node_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_node_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_node_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_node_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_node_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_node_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_node_list(semanage_handle_t * handle, + semanage_node_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_node_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/nodes_policydb.c b/selinux/libsemanage/src/nodes_policydb.c new file mode 100644 index 0000000..7224f00 --- /dev/null +++ b/selinux/libsemanage/src/nodes_policydb.c
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_node; +struct semanage_node_key; +typedef struct semanage_node record_t; +typedef struct semanage_node_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <sepol/nodes.h> +#include <semanage/handle.h> +#include "node_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* NODE RECORD (SEPOL): POLICYDB extension : method table */ +record_policydb_table_t SEMANAGE_NODE_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t) sepol_node_modify, + .set = NULL, + .query = (record_policydb_table_query_t) sepol_node_query, + .count = (record_policydb_table_count_t) sepol_node_count, + .exists = (record_policydb_table_exists_t) sepol_node_exists, + .iterate = (record_policydb_table_iterate_t) sepol_node_iterate, +}; + +int node_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_policydb_init(handle, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + &SEMANAGE_NODE_RTABLE, + &SEMANAGE_NODE_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + + return STATUS_SUCCESS; +} + +void node_policydb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_policydb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/parse_utils.c b/selinux/libsemanage/src/parse_utils.c new file mode 100644 index 0000000..4fb54fc --- /dev/null +++ b/selinux/libsemanage/src/parse_utils.c
@@ -0,0 +1,307 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include <stdio.h> +#include <stdio_ext.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <semanage/handle.h> +#include "parse_utils.h" +#include "debug.h" + +int parse_init(semanage_handle_t * handle, + const char *filename, void *parse_arg, parse_info_t ** info) +{ + + parse_info_t *tmp_info = (parse_info_t *) malloc(sizeof(parse_info_t)); + + if (!tmp_info) { + ERR(handle, + "out of memory, could not allocate parse structure"); + return STATUS_ERR; + } + + tmp_info->filename = filename; + tmp_info->file_stream = NULL; + tmp_info->working_copy = NULL; + tmp_info->orig_line = NULL; + tmp_info->ptr = NULL; + tmp_info->lineno = 0; + tmp_info->parse_arg = parse_arg; + + *info = tmp_info; + return STATUS_SUCCESS; +} + +void parse_release(parse_info_t * info) +{ + + parse_close(info); + parse_dispose_line(info); + free(info); +} + +int parse_open(semanage_handle_t * handle, parse_info_t * info) +{ + + info->file_stream = fopen(info->filename, "r"); + if (!info->file_stream && (errno != ENOENT)) { + ERR(handle, "could not open file %s: %s", + info->filename, strerror(errno)); + return STATUS_ERR; + } + if (info->file_stream) + __fsetlocking(info->file_stream, FSETLOCKING_BYCALLER); + + return STATUS_SUCCESS; +} + +void parse_close(parse_info_t * info) +{ + + if (info->file_stream) + fclose(info->file_stream); + info->file_stream = NULL; +} + +void parse_dispose_line(parse_info_t * info) +{ + if (info->orig_line) { + free(info->orig_line); + info->orig_line = NULL; + } + + if (info->working_copy) { + free(info->working_copy); + info->working_copy = NULL; + } + + info->ptr = NULL; +} + +int parse_skip_space(semanage_handle_t * handle, parse_info_t * info) +{ + + size_t buf_len = 0; + ssize_t len; + int lineno = info->lineno; + char *buffer = NULL; + char *ptr; + + if (info->ptr) { + while (*(info->ptr) && isspace(*(info->ptr))) + info->ptr++; + + if (*(info->ptr)) + return STATUS_SUCCESS; + } + + parse_dispose_line(info); + + while (info->file_stream && + ((len = getline(&buffer, &buf_len, info->file_stream)) > 0)) { + + lineno++; + + /* Eat newline, preceding whitespace */ + if (buffer[len - 1] == '\n') + buffer[len - 1] = '\0'; + + ptr = buffer; + while (*ptr && isspace(*ptr)) + ptr++; + + /* Skip comments and blank lines */ + if ((*ptr) && *ptr != '#') { + char *tmp = strdup(buffer); + if (!tmp) + goto omem; + + info->lineno = lineno; + info->working_copy = buffer; + info->orig_line = tmp; + info->ptr = ptr; + + return STATUS_SUCCESS; + } + } + + free(buffer); + buffer = NULL; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not allocate buffer"); + free(buffer); + return STATUS_ERR; +} + +int parse_assert_noeof(semanage_handle_t * handle, parse_info_t * info) +{ + + if (!info->ptr) { + ERR(handle, "unexpected end of file (%s: %u)", + info->filename, info->lineno); + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +int parse_assert_space(semanage_handle_t * handle, parse_info_t * info) +{ + + if (parse_assert_noeof(handle, info) < 0) + return STATUS_ERR; + + if (*(info->ptr) && !isspace(*(info->ptr))) { + ERR(handle, "missing whitespace (%s: %u):\n%s", + info->filename, info->lineno, info->orig_line); + return STATUS_ERR; + } + + if (parse_skip_space(handle, info) < 0) + return STATUS_ERR; + + return STATUS_SUCCESS; +} + +int parse_assert_ch(semanage_handle_t * handle, + parse_info_t * info, const char ch) +{ + + if (parse_assert_noeof(handle, info) < 0) + return STATUS_ERR; + + if (*(info->ptr) != ch) { + ERR(handle, "expected character \'%c\', but found \'%c\' " + "(%s: %u):\n%s", ch, *(info->ptr), info->filename, + info->lineno, info->orig_line); + return STATUS_ERR; + } + + info->ptr++; + + return STATUS_SUCCESS; +} + +int parse_assert_str(semanage_handle_t * handle, + parse_info_t * info, const char *assert_str) +{ + + size_t len = strlen(assert_str); + + if (parse_assert_noeof(handle, info) < 0) + return STATUS_ERR; + + if (strncmp(info->ptr, assert_str, len)) { + ERR(handle, "experted string \"%s\", but found \"%s\" " + "(%s: %u):\n%s", assert_str, info->ptr, + info->filename, info->lineno, info->orig_line); + + return STATUS_ERR; + } + + info->ptr += len; + return STATUS_SUCCESS; +} + +int parse_optional_ch(parse_info_t * info, const char ch) +{ + + if (!info->ptr) + return STATUS_NODATA; + if (*(info->ptr) != ch) + return STATUS_NODATA; + + info->ptr++; + return STATUS_SUCCESS; +} + +int parse_optional_str(parse_info_t * info, const char *str) +{ + size_t len = strlen(str); + + if (strncmp(info->ptr, str, len)) + return STATUS_NODATA; + + info->ptr += len; + return STATUS_SUCCESS; +} + +int parse_fetch_int(semanage_handle_t * handle, + parse_info_t * info, int *num, char delim) +{ + + char *str = NULL; + char *test = NULL; + int value = 0; + + if (parse_fetch_string(handle, info, &str, delim) < 0) + goto err; + + if (!isdigit((int)*str)) { + ERR(handle, "expected a numeric value: (%s: %u)\n%s", + info->filename, info->lineno, info->orig_line); + goto err; + } + + value = strtol(str, &test, 10); + if (*test != '\0') { + ERR(handle, "could not parse numeric value \"%s\": " + "(%s: %u)\n%s", str, info->filename, + info->lineno, info->orig_line); + goto err; + } + + *num = value; + free(str); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not fetch numeric value"); + free(str); + return STATUS_ERR; +} + +int parse_fetch_string(semanage_handle_t * handle, + parse_info_t * info, char **str, char delim) +{ + + char *start = info->ptr; + int len = 0; + char *tmp_str = NULL; + + if (parse_assert_noeof(handle, info) < 0) + goto err; + + while (*(info->ptr) && !isspace(*(info->ptr)) && + (*(info->ptr) != delim)) { + info->ptr++; + len++; + } + + if (len == 0) { + ERR(handle, "expected non-empty string, but did not " + "find one (%s: %u):\n%s", info->filename, info->lineno, + info->orig_line); + goto err; + } + + tmp_str = (char *)malloc(len + 1); + if (!tmp_str) { + ERR(handle, "out of memory"); + goto err; + } + + strncpy(tmp_str, start, len); + *(tmp_str + len) = '\0'; + *str = tmp_str; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not fetch string value"); + return STATUS_ERR; +}
diff --git a/selinux/libsemanage/src/parse_utils.h b/selinux/libsemanage/src/parse_utils.h new file mode 100644 index 0000000..0f33486 --- /dev/null +++ b/selinux/libsemanage/src/parse_utils.h
@@ -0,0 +1,82 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_PARSE_UTILS_INTERNAL_H_ +#define _SEMANAGE_PARSE_UTILS_INTERNAL_H_ + +#include <stdio.h> +#include <semanage/handle.h> + +typedef struct parse_info { + unsigned int lineno; /* Current line number */ + char *orig_line; /* Original copy of the line being parsed */ + char *working_copy; /* Working copy of the line being parsed */ + char *ptr; /* Current parsing location */ + + const char *filename; /* Input stream file name */ + FILE *file_stream; /* Input stream handle */ + + void *parse_arg; /* Caller supplied argument */ +} parse_info_t; + +/* Initialize structure */ +extern int parse_init(semanage_handle_t * handle, + const char *filename, + void *parse_arg, parse_info_t ** info); + +/* Release structure */ +extern void parse_release(parse_info_t * info); + +/* Open file */ +extern int parse_open(semanage_handle_t * handle, parse_info_t * info); + +/* Close file */ +extern void parse_close(parse_info_t * info); + +/* Release resources for current line */ +extern void parse_dispose_line(parse_info_t * info); + +/* Skip all whitespace and comments */ +extern int parse_skip_space(semanage_handle_t * handle, parse_info_t * info); + +/* Throw an error if we're at the EOF */ +extern int parse_assert_noeof(semanage_handle_t * handle, parse_info_t * info); + +/* Throw an error if no whitespace follows, + * otherwise eat the whitespace */ +extern int parse_assert_space(semanage_handle_t * handle, parse_info_t * info); + +/* Throw an error if the specified character + * does not follow, otherwise eat that character */ +extern int parse_assert_ch(semanage_handle_t * handle, + parse_info_t * info, const char ch); + +/* Throw an error if the specified string + * does not follow is not found, otherwise + * eat the string */ +extern int parse_assert_str(semanage_handle_t * handle, + parse_info_t * info, const char *assert_str); + +/* Eat the optional character, if found, + * or return STATUS_NODATA */ +extern int parse_optional_ch(parse_info_t * info, const char ch); + +/* Eat the optional string, if found, + * or return STATUS_NODATA */ +extern int parse_optional_str(parse_info_t * info, const char *str); + +/* Extract the next integer, and move + * the read pointer past it. Stop if + * the optional character delim is encountered, + * or if whitespace/eof is encountered */ +int parse_fetch_int(semanage_handle_t * hgandle, + parse_info_t * info, int *num, char delim); + +/* Extract the next string (delimited by + * whitespace), and move the read pointer past it. + * Stop of the optional character delim is encountered, + * or if whitespace/eof is encountered. Fail if the + * string is of length 0. */ +extern int parse_fetch_string(semanage_handle_t * handle, + parse_info_t * info, char **str_ptr, char delim); + +#endif
diff --git a/selinux/libsemanage/src/policy.h b/selinux/libsemanage/src/policy.h new file mode 100644 index 0000000..f127156 --- /dev/null +++ b/selinux/libsemanage/src/policy.h
@@ -0,0 +1,106 @@ +/* Author: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2005 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SEMANAGE_POLICY_INTERNAL_H_ +#define _SEMANAGE_POLICY_INTERNAL_H_ + +#include "modules.h" + +/* Circular dependency */ +struct semanage_handle; + +/* Backend dependent portion */ +struct semanage_policy_table { + + /* Returns the current policy serial/commit number + * A negative number is returned in case of failre */ + int (*get_serial) (struct semanage_handle *); + + /* Destroy a connection */ + void (*destroy) (struct semanage_handle *); + + /* Disconnect from policy */ + int (*disconnect) (struct semanage_handle *); + + /* Begin a policy transaction */ + int (*begin_trans) (struct semanage_handle *); + + /* Commit a policy transaction */ + int (*commit) (struct semanage_handle *); + + /* Install a policy module */ + int (*install) (struct semanage_handle *, char *, size_t, const char *, const char *); + + /* Install a policy module */ + int (*install_file) (struct semanage_handle *, const char *); + + /* Extract a policy module */ + int (*extract) (struct semanage_handle *, + semanage_module_key_t *, + int extract_cil, + void **, + size_t *, + semanage_module_info_t **); + + /* Remove a policy module */ + int (*remove) (struct semanage_handle *, char *); + + /* List policy modules */ + int (*list) (struct semanage_handle *, semanage_module_info_t **, + int *); + + /* Get module enabled status */ + int (*get_enabled) (struct semanage_handle *sh, + const semanage_module_key_t *key, + int *enabled); + + /* Set module enabled status */ + int (*set_enabled) (struct semanage_handle *sh, + const semanage_module_key_t *key, + int enabled); + + /* Get a module info */ + int (*get_module_info) (struct semanage_handle *, + const semanage_module_key_t *, + semanage_module_info_t **); + + /* List all policy modules */ + int (*list_all) (struct semanage_handle *, + semanage_module_info_t **, + int *); + + /* Install via module info */ + int (*install_info) (struct semanage_handle *, + const semanage_module_info_t *, + char *, + size_t); + + /* Remove via module key */ + int (*remove_key) (struct semanage_handle *, + const semanage_module_key_t *); +}; + +/* Should be backend independent */ +extern int semanage_base_merge_components(struct semanage_handle *handle); + +extern int semanage_commit_components(struct semanage_handle *handle); + +#endif
diff --git a/selinux/libsemanage/src/policy_components.c b/selinux/libsemanage/src/policy_components.c new file mode 100644 index 0000000..d31bd48 --- /dev/null +++ b/selinux/libsemanage/src/policy_components.c
@@ -0,0 +1,239 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include <stdlib.h> +#include "policy.h" +#include "handle.h" +#include "database.h" +#include "modules.h" +#include "debug.h" + +/* Powers of two only */ +#define MODE_SET 1 +#define MODE_MODIFY 2 +#define MODE_SORT 4 + +static int clear_obsolete(semanage_handle_t * handle, + record_t ** records, + unsigned int nrecords, + dbase_config_t * src, dbase_config_t * dst) +{ + + record_key_t *key = NULL; + unsigned int i; + + dbase_table_t *src_dtable = src->dtable; + dbase_table_t *dst_dtable = dst->dtable; + record_table_t *rtable = src_dtable->get_rtable(src->dbase); + + for (i = 0; i < nrecords; i++) { + int exists; + + if (rtable->key_extract(handle, records[i], &key) < 0) + goto err; + + if (dst_dtable->exists(handle, dst->dbase, key, &exists) < 0) + goto err; + + if (!exists) { + if (src_dtable->del(handle, src->dbase, key) < 0) + goto err; + + rtable->free(records[i]); + records[i] = NULL; + + /* FIXME: notice to user */ + /* INFO(handle, "boolean %s is obsolete, unsetting configured value..."); */ + } + + rtable->key_free(key); + } + + return STATUS_SUCCESS; + + err: + /* FIXME: handle error */ + rtable->key_free(key); + return STATUS_ERR; +} + +static int load_records(semanage_handle_t * handle, + dbase_config_t * dst, + record_t ** records, unsigned int nrecords, int mode) +{ + + unsigned int i; + record_key_t *rkey = NULL; + + dbase_t *dbase = dst->dbase; + dbase_table_t *dtable = dst->dtable; + record_table_t *rtable = dtable->get_rtable(dbase); + + for (i = 0; i < nrecords; i++) { + + /* Possibly obsoleted */ + if (!records[i]) + continue; + + if (rtable->key_extract(handle, records[i], &rkey) < 0) + goto err; + + if (mode & MODE_SET && + dtable->set(handle, dbase, rkey, records[i]) < 0) + goto err; + + else if (mode & MODE_MODIFY && + dtable->modify(handle, dbase, rkey, records[i]) < 0) + goto err; + + rtable->key_free(rkey); + } + + return STATUS_SUCCESS; + + err: + /* FIXME: handle error */ + rtable->key_free(rkey); + return STATUS_ERR; +} + +typedef struct load_table { + dbase_config_t *src; + dbase_config_t *dst; + int mode; +} load_table_t; + +/* This function must be called AFTER all modules are loaded. + * Modules could be represented as a database, in which case + * they should be loaded at the beginning of this function */ + +int semanage_base_merge_components(semanage_handle_t * handle) +{ + + unsigned int i, j; + int rc = STATUS_SUCCESS; + + /* Order is important here - change things carefully. + * System components first, local next. Verify runs with + * mutual dependencies are ran after everything is merged */ + load_table_t components[] = { + + {semanage_user_base_dbase_local(handle), + semanage_user_base_dbase_policy(handle), MODE_MODIFY}, + + {semanage_user_extra_dbase_local(handle), + semanage_user_extra_dbase_policy(handle), MODE_MODIFY}, + + {semanage_port_dbase_local(handle), + semanage_port_dbase_policy(handle), MODE_MODIFY}, + + {semanage_iface_dbase_local(handle), + semanage_iface_dbase_policy(handle), MODE_MODIFY}, + + {semanage_bool_dbase_local(handle), + semanage_bool_dbase_policy(handle), MODE_SET}, + + {semanage_seuser_dbase_local(handle), + semanage_seuser_dbase_policy(handle), MODE_MODIFY}, + + {semanage_node_dbase_local(handle), + semanage_node_dbase_policy(handle), MODE_MODIFY | MODE_SORT}, + }; + const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]); + + /* Merge components into policy (and validate) */ + for (i = 0; i < CCOUNT; i++) { + + record_t **records = NULL; + unsigned int nrecords = 0; + + dbase_config_t *src = components[i].src; + dbase_config_t *dst = components[i].dst; + int mode = components[i].mode; + record_table_t *rtable = src->dtable->get_rtable(src->dbase); + + /* Must invoke cache function first */ + if (src->dtable->cache(handle, src->dbase) < 0) + goto err; + if (dst->dtable->cache(handle, dst->dbase) < 0) + goto err; + + /* List all records */ + if (src->dtable->list(handle, src->dbase, + &records, &nrecords) < 0) + goto err; + + /* Sort records on MODE_SORT */ + if (mode & MODE_SORT) { + qsort(records, nrecords, sizeof(record_t *), + (int (*)(const void *, const void *))rtable-> + compare2_qsort); + } + + /* Clear obsolete ones for MODE_SET */ + if (mode & MODE_SET && + clear_obsolete(handle, records, nrecords, src, dst) < 0) { + rc = STATUS_ERR; + goto dbase_exit; + } + + /* Load records */ + if (load_records(handle, dst, records, nrecords, mode) < 0) { + + rc = STATUS_ERR; + goto dbase_exit; + } + + /* Cleanup */ + dbase_exit: + for (j = 0; j < nrecords; j++) + rtable->free(records[j]); + free(records); + + /* Abort on error */ + if (rc < 0) + goto err; + } + + return rc; + + err: + ERR(handle, "could not merge local modifications into policy"); + return STATUS_ERR; +} + +int semanage_commit_components(semanage_handle_t * handle) +{ + + int i; + dbase_config_t *components[] = { + semanage_iface_dbase_local(handle), + semanage_bool_dbase_local(handle), + semanage_user_base_dbase_local(handle), + semanage_user_extra_dbase_local(handle), + semanage_user_extra_dbase_policy(handle), + semanage_port_dbase_local(handle), + semanage_fcontext_dbase_local(handle), + semanage_fcontext_dbase_policy(handle), + semanage_seuser_dbase_local(handle), + semanage_seuser_dbase_policy(handle), + semanage_bool_dbase_active(handle), + semanage_node_dbase_local(handle), + }; + const int CCOUNT = sizeof(components) / sizeof(components[0]); + + for (i = 0; i < CCOUNT; i++) { + /* Flush to disk */ + if (components[i]->dtable->flush(handle, components[i]->dbase) < + 0) + goto err; + } + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not commit local/active modifications"); + + for (i = 0; i < CCOUNT; i++) + components[i]->dtable->drop_cache(components[i]->dbase); + return STATUS_ERR; +}
diff --git a/selinux/libsemanage/src/port_internal.h b/selinux/libsemanage/src/port_internal.h new file mode 100644 index 0000000..ebd2bc8 --- /dev/null +++ b/selinux/libsemanage/src/port_internal.h
@@ -0,0 +1,51 @@ +#ifndef _SEMANAGE_PORT_INTERNAL_H_ +#define _SEMANAGE_PORT_INTERNAL_H_ + +#include <semanage/port_record.h> +#include <semanage/ports_local.h> +#include <semanage/ports_policy.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_port_create) + hidden_proto(semanage_port_compare) + hidden_proto(semanage_port_compare2) + hidden_proto(semanage_port_clone) + hidden_proto(semanage_port_free) + hidden_proto(semanage_port_key_extract) + hidden_proto(semanage_port_key_free) + hidden_proto(semanage_port_get_high) + hidden_proto(semanage_port_get_low) + hidden_proto(semanage_port_set_port) + hidden_proto(semanage_port_set_range) + hidden_proto(semanage_port_get_proto) + hidden_proto(semanage_port_set_proto) + hidden_proto(semanage_port_get_proto_str) + hidden_proto(semanage_port_get_con) + hidden_proto(semanage_port_set_con) + hidden_proto(semanage_port_list_local) + +/* PORT RECORD: method table */ +extern record_table_t SEMANAGE_PORT_RTABLE; + +extern int port_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void port_file_dbase_release(dbase_config_t * dconfig); + +extern int port_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void port_policydb_dbase_release(dbase_config_t * dconfig); + +extern int hidden semanage_port_validate_local(semanage_handle_t * handle); + +/* ==== Internal (to ports) API === */ + +hidden int semanage_port_compare2_qsort(const semanage_port_t ** port, + const semanage_port_t ** port2); + +#endif
diff --git a/selinux/libsemanage/src/port_record.c b/selinux/libsemanage/src/port_record.c new file mode 100644 index 0000000..b878ca7 --- /dev/null +++ b/selinux/libsemanage/src/port_record.c
@@ -0,0 +1,192 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_port_t (Network Port) + * Object: semanage_port_key_t (Network Port Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/context_record.h> +#include <sepol/port_record.h> + +typedef sepol_context_t semanage_context_t; +typedef sepol_port_t semanage_port_t; +typedef sepol_port_key_t semanage_port_key_t; +#define _SEMANAGE_PORT_DEFINED_ +#define _SEMANAGE_CONTEXT_DEFINED_ + +typedef semanage_port_t record_t; +typedef semanage_port_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "port_internal.h" +#include "handle.h" +#include "database.h" + +/* Key */ +int semanage_port_compare(const semanage_port_t * port, + const semanage_port_key_t * key) +{ + + return sepol_port_compare(port, key); +} + +hidden_def(semanage_port_compare) + +int semanage_port_compare2(const semanage_port_t * port, + const semanage_port_t * port2) +{ + + return sepol_port_compare2(port, port2); +} + +hidden_def(semanage_port_compare2) + +hidden int semanage_port_compare2_qsort(const semanage_port_t ** port, + const semanage_port_t ** port2) +{ + + return sepol_port_compare2(*port, *port2); +} + +int semanage_port_key_create(semanage_handle_t * handle, + int low, int high, int proto, + semanage_port_key_t ** key_ptr) +{ + + return sepol_port_key_create(handle->sepolh, low, high, proto, key_ptr); +} + +int semanage_port_key_extract(semanage_handle_t * handle, + const semanage_port_t * port, + semanage_port_key_t ** key_ptr) +{ + + return sepol_port_key_extract(handle->sepolh, port, key_ptr); +} + +hidden_def(semanage_port_key_extract) + +void semanage_port_key_free(semanage_port_key_t * key) +{ + + sepol_port_key_free(key); +} + +hidden_def(semanage_port_key_free) + +/* Protocol */ +int semanage_port_get_proto(const semanage_port_t * port) +{ + + return sepol_port_get_proto(port); +} + +hidden_def(semanage_port_get_proto) + +void semanage_port_set_proto(semanage_port_t * port, int proto) +{ + + sepol_port_set_proto(port, proto); +} + +hidden_def(semanage_port_set_proto) + +const char *semanage_port_get_proto_str(int proto) +{ + + return sepol_port_get_proto_str(proto); +} + +hidden_def(semanage_port_get_proto_str) + +/* Port */ +int semanage_port_get_low(const semanage_port_t * port) +{ + + return sepol_port_get_low(port); +} + +hidden_def(semanage_port_get_low) + +int semanage_port_get_high(const semanage_port_t * port) +{ + + return sepol_port_get_high(port); +} + +hidden_def(semanage_port_get_high) + +void semanage_port_set_port(semanage_port_t * port, int port_num) +{ + + sepol_port_set_port(port, port_num); +} + +hidden_def(semanage_port_set_port) + +void semanage_port_set_range(semanage_port_t * port, int low, int high) +{ + + sepol_port_set_range(port, low, high); +} + +hidden_def(semanage_port_set_range) + +/* Context */ +semanage_context_t *semanage_port_get_con(const semanage_port_t * port) +{ + + return sepol_port_get_con(port); +} + +hidden_def(semanage_port_get_con) + +int semanage_port_set_con(semanage_handle_t * handle, + semanage_port_t * port, semanage_context_t * con) +{ + + return sepol_port_set_con(handle->sepolh, port, con); +} + +hidden_def(semanage_port_set_con) + +/* Create/Clone/Destroy */ +int semanage_port_create(semanage_handle_t * handle, + semanage_port_t ** port_ptr) +{ + + return sepol_port_create(handle->sepolh, port_ptr); +} + +hidden_def(semanage_port_create) + +int semanage_port_clone(semanage_handle_t * handle, + const semanage_port_t * port, + semanage_port_t ** port_ptr) +{ + + return sepol_port_clone(handle->sepolh, port, port_ptr); +} + +hidden_def(semanage_port_clone) + +void semanage_port_free(semanage_port_t * port) +{ + + sepol_port_free(port); +} + +hidden_def(semanage_port_free) + +/* Port base functions */ +record_table_t SEMANAGE_PORT_RTABLE = { + .create = semanage_port_create, + .key_extract = semanage_port_key_extract, + .key_free = semanage_port_key_free, + .clone = semanage_port_clone, + .compare = semanage_port_compare, + .compare2 = semanage_port_compare2, + .compare2_qsort = semanage_port_compare2_qsort, + .free = semanage_port_free, +};
diff --git a/selinux/libsemanage/src/ports_file.c b/selinux/libsemanage/src/ports_file.c new file mode 100644 index 0000000..46ee2f0 --- /dev/null +++ b/selinux/libsemanage/src/ports_file.c
@@ -0,0 +1,187 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_port; +struct semanage_port_key; +typedef struct semanage_port record_t; +typedef struct semanage_port_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <semanage/handle.h> +#include "port_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int port_print(semanage_handle_t * handle, + semanage_port_t * port, FILE * str) +{ + + char *con_str = NULL; + + int low = semanage_port_get_low(port); + int high = semanage_port_get_high(port); + int proto = semanage_port_get_proto(port); + const char *proto_str = semanage_port_get_proto_str(proto); + semanage_context_t *con = semanage_port_get_con(port); + + if (fprintf(str, "portcon %s ", proto_str) < 0) + goto err; + + if (low == high) { + if (fprintf(str, "%d ", low) < 0) + goto err; + } else { + if (fprintf(str, "%d - %d ", low, high) < 0) + goto err; + } + + if (semanage_context_to_string(handle, con, &con_str) < 0) + goto err; + if (fprintf(str, "%s\n", con_str) < 0) + goto err; + + free(con_str); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not print port range %u - %u (%s) to stream", + low, high, proto_str); + free(con_str); + return STATUS_ERR; +} + +static int port_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_port_t * port) +{ + + int low, high; + char *str = NULL; + semanage_context_t *con = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Header */ + if (parse_assert_str(handle, info, "portcon") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Protocol */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (!strcasecmp(str, "tcp")) + semanage_port_set_proto(port, SEMANAGE_PROTO_TCP); + else if (!strcasecmp(str, "udp")) + semanage_port_set_proto(port, SEMANAGE_PROTO_UDP); + else { + ERR(handle, "invalid protocol \"%s\" (%s: %u):\n%s", str, + info->filename, info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + /* Range/Port */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_int(handle, info, &low, '-') < 0) + goto err; + + /* If range (-) does not follow immediately, require a space + * In other words, the space here is optional, but only + * in the ranged case, not in the single port case, + * so do a custom test */ + if (*(info->ptr) && *(info->ptr) != '-') { + if (parse_assert_space(handle, info) < 0) + goto err; + } + + if (parse_optional_ch(info, '-') != STATUS_NODATA) { + + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_fetch_int(handle, info, &high, ' ') < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + semanage_port_set_range(port, low, high); + } else + semanage_port_set_port(port, low); + + /* Port context */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_context_from_string(handle, str, &con) < 0) { + ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s", + str, info->filename, info->lineno, info->orig_line); + goto err; + } + if (con == NULL) { + ERR(handle, "<<none>> context is not valid " + "for ports (%s: %u):\n%s", info->filename, + info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_port_set_con(handle, port, con) < 0) + goto err; + + if (parse_assert_space(handle, info) < 0) + goto err; + + semanage_context_free(con); + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse port record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* PORT RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_PORT_FILE_RTABLE = { + .parse = port_parse, + .print = port_print, +}; + +int port_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_PORT_RTABLE, + &SEMANAGE_PORT_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void port_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/ports_local.c b/selinux/libsemanage/src/ports_local.c new file mode 100644 index 0000000..ffd5a83 --- /dev/null +++ b/selinux/libsemanage/src/ports_local.c
@@ -0,0 +1,144 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_port; +struct semanage_port_key; +typedef struct semanage_port_key record_key_t; +typedef struct semanage_port record_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include "port_internal.h" +#include "debug.h" +#include "handle.h" +#include "database.h" + +int semanage_port_modify_local(semanage_handle_t * handle, + const semanage_port_key_t * key, + const semanage_port_t * data) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_port_del_local(semanage_handle_t * handle, + const semanage_port_key_t * key) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_port_query_local(semanage_handle_t * handle, + const semanage_port_key_t * key, + semanage_port_t ** response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_port_exists_local(semanage_handle_t * handle, + const semanage_port_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_port_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_port_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_port_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_port_list_local(semanage_handle_t * handle, + semanage_port_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_port_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +} + +hidden_def(semanage_port_list_local) + +int hidden semanage_port_validate_local(semanage_handle_t * handle) +{ + + semanage_port_t **ports = NULL; + unsigned int nports = 0; + unsigned int i = 0, j = 0; + + /* List and sort the ports */ + if (semanage_port_list_local(handle, &ports, &nports) < 0) + goto err; + qsort(ports, nports, sizeof(semanage_port_t *), + (int (*)(const void *, const void *)) + &semanage_port_compare2_qsort); + + /* Test each port for overlap */ + while (i < nports) { + + int proto = semanage_port_get_proto(ports[i]); + int low = semanage_port_get_low(ports[i]); + int high = semanage_port_get_high(ports[i]); + const char *proto_str = semanage_port_get_proto_str(proto); + + const char *proto_str2; + int proto2, low2, high2; + + /* Find the first port with matching + protocol to compare against */ + do { + if (j == nports - 1) + goto next; + j++; + proto2 = semanage_port_get_proto(ports[j]); + low2 = semanage_port_get_low(ports[j]); + high2 = semanage_port_get_high(ports[j]); + proto_str2 = semanage_port_get_proto_str(proto2); + + } while (proto != proto2); + + /* Overlap detected */ + if (low2 <= high) { + ERR(handle, "port overlap between ranges " + "%u - %u (%s) <--> %u - %u (%s).", + low, high, proto_str, low2, high2, proto_str2); + goto invalid; + } + + /* If closest port of matching protocol doesn't overlap with + * test port, neither do the rest of them, because that's + * how the sort function works on ports - lower bound + * ports come first */ + next: + i++; + j = i; + } + + for (i = 0; i < nports; i++) + semanage_port_free(ports[i]); + free(ports); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not complete ports validity check"); + + invalid: + for (i = 0; i < nports; i++) + semanage_port_free(ports[i]); + free(ports); + return STATUS_ERR; +}
diff --git a/selinux/libsemanage/src/ports_policy.c b/selinux/libsemanage/src/ports_policy.c new file mode 100644 index 0000000..1bcd3fa --- /dev/null +++ b/selinux/libsemanage/src/ports_policy.c
@@ -0,0 +1,52 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_port; +struct semanage_port_key; +typedef struct semanage_port_key record_key_t; +typedef struct semanage_port record_t; +#define DBASE_RECORD_DEFINED + +#include "port_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_port_query(semanage_handle_t * handle, + const semanage_port_key_t * key, + semanage_port_t ** response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_port_exists(semanage_handle_t * handle, + const semanage_port_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_port_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_port_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_port_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_port_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_port_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_port_list(semanage_handle_t * handle, + semanage_port_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_port_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/ports_policydb.c b/selinux/libsemanage/src/ports_policydb.c new file mode 100644 index 0000000..37d7deb --- /dev/null +++ b/selinux/libsemanage/src/ports_policydb.c
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_port; +struct semanage_port_key; +typedef struct semanage_port record_t; +typedef struct semanage_port_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <sepol/ports.h> +#include <semanage/handle.h> +#include "port_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* PORT RECORD (SEPOL): POLICYDB extension : method table */ +record_policydb_table_t SEMANAGE_PORT_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t) sepol_port_modify, + .set = NULL, + .query = (record_policydb_table_query_t) sepol_port_query, + .count = (record_policydb_table_count_t) sepol_port_count, + .exists = (record_policydb_table_exists_t) sepol_port_exists, + .iterate = (record_policydb_table_iterate_t) sepol_port_iterate, +}; + +int port_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_policydb_init(handle, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + &SEMANAGE_PORT_RTABLE, + &SEMANAGE_PORT_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + + return STATUS_SUCCESS; +} + +void port_policydb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_policydb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/pywrap-test.py b/selinux/libsemanage/src/pywrap-test.py new file mode 100644 index 0000000..25b668d --- /dev/null +++ b/selinux/libsemanage/src/pywrap-test.py
@@ -0,0 +1,1141 @@ +#!/usr/bin/python +import sys +import getopt +import semanage + +usage = "\ +Choose one of the following tests:\n\ +-m for modules\n\ +-u for users\n\ +-U for add user (warning this will write!)\n\ +-s for seusers\n\ +-S for add seuser (warning this will write!)\n\ +-p for ports\n\ +-P for add port (warning this will write!)\n\ +-f for file contexts \n\ +-F for add file context (warning this will write!)\n\ +-i for network interfaces \n\ +-I for add network interface (warning this will write!)\n\ +-b for booleans \n\ +-B for add boolean (warning this will write!)\n\ +-c for aCtive booleans\n\ +-C for set aCtive boolean (warning this will write!)\n\n\ +-n for network nodes\n\ +-N for add node (warning this will write!)\n\n\ +Other options:\n\ +-h for this help\n\ +-v for verbose output\ +" + +class Usage(Exception): + def __init__(self, msg): + Exception.__init__(self) + self.msg = msg + +class Status(Exception): + def __init__(self, msg): + Exception.__init__(self) + self.msg = msg + +class Error(Exception): + def __init__(self, msg): + Exception.__init__(self) + self.msg = msg + +class Tests: + def __init__(self): + self.all = False + self.users = False + self.writeuser = False + self.seusers = False + self.writeseuser = False + self.ports = False + self.writeport = False + self.fcontexts = False + self.writefcontext = False + self.interfaces = False + self.writeinterface = False + self.booleans = False + self.writeboolean = False + self.abooleans = False + self.writeaboolean = False + self.nodes = False + self.writenode = False + self.modules = False + self.verbose = False + + def selected(self): + return (self.all or self.users or self.modules or self.seusers or self.ports or self.fcontexts or self.interfaces or self.booleans or self.abooleans or self.writeuser or self.writeseuser or self.writeport or self.writefcontext or self.writeinterface or self.writeboolean or self.writeaboolean or self.nodes or self.writenode) + + def run(self, handle): + if (self.users or self.all): + self.test_users(handle) + print "" + if (self.seusers or self.all): + self.test_seusers(handle) + print "" + if (self.ports or self.all): + self.test_ports(handle) + print "" + if (self.modules or self.all): + self.test_modules(handle) + print "" + if (self.fcontexts or self.all): + self.test_fcontexts(handle) + print "" + if (self.interfaces or self.all): + self.test_interfaces(handle) + print "" + if (self.booleans or self.all): + self.test_booleans(handle) + print "" + if (self.abooleans or self.all): + self.test_abooleans(handle) + print "" + if (self.nodes or self.all): + self.test_nodes(handle) + print "" + if (self.writeuser or self.all): + self.test_writeuser(handle) + print "" + if (self.writeseuser or self.all): + self.test_writeseuser(handle) + print "" + if (self.writeport or self.all): + self.test_writeport(handle) + print "" + if (self.writefcontext or self.all): + self.test_writefcontext(handle) + print "" + if (self.writeinterface or self.all): + self.test_writeinterface(handle) + print "" + if (self.writeboolean or self.all): + self.test_writeboolean(handle) + print "" + if (self.writeaboolean or self.all): + self.test_writeaboolean(handle) + print "" + if (self.writenode or self.all): + self.test_writenode(handle) + print "" + + def test_modules(self,sh): + print "Testing modules..." + + (trans_cnt, mlist, mlist_size) = semanage.semanage_module_list(sh) + + print "Transaction number: ", trans_cnt + print "Module list size: ", mlist_size + if self.verbose: print "List reference: ", mlist + + if (mlist_size == 0): + print "No modules installed!" + print "This is not necessarily a test failure." + return + for idx in range(mlist_size): + module = semanage.semanage_module_list_nth(mlist, idx) + if self.verbose: print "Module reference: ", module + print "Module name: ", semanage.semanage_module_get_name(module) + + def test_seusers(self,sh): + print "Testing seusers..." + + (status, slist) = semanage.semanage_seuser_list(sh) + if status < 0: + raise Error("Could not list seusers") + print "Query status (commit number): ", status + + if ( len(slist) == 0): + print "No seusers found!" + print "This is not necessarily a test failure." + return + for seuser in slist: + if self.verbose: print "seseuser reference: ", seuser + print "seuser name: ", semanage.semanage_seuser_get_name(seuser) + print " seuser mls range: ", semanage.semanage_seuser_get_mlsrange(seuser) + print " seuser sename: ", semanage.semanage_seuser_get_sename(seuser) + semanage.semanage_seuser_free(seuser) + + def test_users(self,sh): + print "Testing users..." + + (status, ulist) = semanage.semanage_user_list(sh) + if status < 0: + raise Error("Could not list users") + print "Query status (commit number): ", status + + if ( len(ulist) == 0): + print "No users found!" + print "This is not necessarily a test failure." + return + for user in ulist: + if self.verbose: print "User reference: ", user + print "User name: ", semanage.semanage_user_get_name(user) + print " User labeling prefix: ", semanage.semanage_user_get_prefix(user) + print " User mls level: ", semanage.semanage_user_get_mlslevel(user) + print " User mls range: ", semanage.semanage_user_get_mlsrange(user) + print " User number of roles: ", semanage.semanage_user_get_num_roles(user) + print " User roles: " + (status, rlist) = semanage.semanage_user_get_roles(sh, user) + if status < 0: + raise Error("Could not get user roles") + + for role in rlist: + print " ", role + + semanage.semanage_user_free(user) + + def test_ports(self,sh): + print "Testing ports..." + + (status, plist) = semanage.semanage_port_list(sh) + if status < 0: + raise Error("Could not list ports") + print "Query status (commit number): ", status + + if ( len(plist) == 0): + print "No ports found!" + print "This is not necessarily a test failure." + return + for port in plist: + if self.verbose: print "Port reference: ", port + low = semanage.semanage_port_get_low(port) + high = semanage.semanage_port_get_high(port) + con = semanage.semanage_port_get_con(port) + proto = semanage.semanage_port_get_proto(port) + proto_str = semanage.semanage_port_get_proto_str(proto) + if low == high: + range_str = str(low) + else: + range_str = str(low) + "-" + str(high) + (rc, con_str) = semanage.semanage_context_to_string(sh,con) + if rc < 0: con_str = "" + print "Port: ", range_str, " ", proto_str, " Context: ", con_str + semanage.semanage_port_free(port) + + def test_fcontexts(self,sh): + print "Testing file contexts..." + + (status, flist) = semanage.semanage_fcontext_list(sh) + if status < 0: + raise Error("Could not list file contexts") + print "Query status (commit number): ", status + + if (len(flist) == 0): + print "No file contexts found!" + print "This is not necessarily a test failure." + return + for fcon in flist: + if self.verbose: print "File Context reference: ", fcon + expr = semanage.semanage_fcontext_get_expr(fcon) + type = semanage.semanage_fcontext_get_type(fcon) + type_str = semanage.semanage_fcontext_get_type_str(type) + con = semanage.semanage_fcontext_get_con(fcon) + if not con: + con_str = "<<none>>" + else: + (rc, con_str) = semanage.semanage_context_to_string(sh,con) + if rc < 0: con_str = "" + print "File Expr: ", expr, " [", type_str, "] Context: ", con_str + semanage.semanage_fcontext_free(fcon) + + def test_interfaces(self,sh): + print "Testing network interfaces..." + + (status, ilist) = semanage.semanage_iface_list(sh) + if status < 0: + raise Error("Could not list interfaces") + print "Query status (commit number): ", status + + if (len(ilist) == 0): + print "No network interfaces found!" + print "This is not necessarily a test failure." + return + for iface in ilist: + if self.verbose: print "Interface reference: ", iface + name = semanage.semanage_iface_get_name(iface) + msg_con = semanage.semanage_iface_get_msgcon(iface) + if_con = semanage.semanage_iface_get_ifcon(iface) + (rc, msg_con_str) = semanage.semanage_context_to_string(sh,msg_con) + if rc < 0: msg_con_str = "" + (rc, if_con_str) = semanage.semanage_context_to_string(sh, if_con) + if rc < 0: if_con_str = "" + print "Interface: ", name, " Context: ", if_con_str, " Message Context: ", msg_con_str + semanage.semanage_iface_free(iface) + + def test_booleans(self,sh): + print "Testing booleans..." + + (status, blist) = semanage.semanage_bool_list(sh) + if status < 0: + raise Error("Could not list booleans") + print "Query status (commit number): ", status + + if (len(blist) == 0): + print "No booleans found!" + print "This is not necessarily a test failure." + return + for pbool in blist: + if self.verbose: print "Boolean reference: ", pbool + name = semanage.semanage_bool_get_name(pbool) + value = semanage.semanage_bool_get_value(pbool) + print "Boolean: ", name, " Value: ", value + semanage.semanage_bool_free(pbool) + + def test_abooleans(self,sh): + print "Testing active booleans..." + + (status, ablist) = semanage.semanage_bool_list_active(sh) + if status < 0: + raise Error("Could not list active booleans") + print "Query status (commit number): ", status + + if (len(ablist) == 0): + print "No active booleans found!" + print "This is not necessarily a test failure." + return + for abool in ablist: + if self.verbose: print "Active boolean reference: ", abool + name = semanage.semanage_bool_get_name(abool) + value = semanage.semanage_bool_get_value(abool) + print "Active Boolean: ", name, " Value: ", value + semanage.semanage_bool_free(abool) + + def test_nodes(self,sh): + print "Testing network nodes..." + + (status, nlist) = semanage.semanage_node_list(sh) + if status < 0: + raise Error("Could not list network nodes") + print "Query status (commit number): ", status + + if (len(nlist) == 0): + print "No network nodes found!" + print "This is not necessarily a test failure." + return + for node in nlist: + if self.verbose: print "Network node reference: ", node + + (status, addr) = semanage.semanage_node_get_addr(sh, node) + if status < 0: addr = "" + + (status, mask) = semanage.semanage_node_get_mask(sh, node) + if status < 0: mask = "" + + proto = semanage.semanage_node_get_proto(node) + proto_str = semanage.semanage_node_get_proto_str(proto) + con = semanage.semanage_node_get_con(node) + + (status, con_str) = semanage.semanage_context_to_string(sh, con) + if status < 0: con_str = "" + + print "Network Node: ", addr, "/", mask, " (", proto_str, ")", "Context: ", con_str + semanage.semanage_node_free(node) + + def test_writeuser(self,sh): + print "Testing user write..." + + (status, user) = semanage.semanage_user_create(sh) + if status < 0: + raise Error("Could not create user object") + if self.verbose: print "User object created" + + status = semanage.semanage_user_set_name(sh,user, "testPyUser") + if status < 0: + raise Error("Could not set user name") + if self.verbose: print "User name set: ", semanage.semanage_user_get_name(user) + + status = semanage.semanage_user_add_role(sh, user, "user_r") + if status < 0: + raise Error("Could not add role") + + status = semanage.semanage_user_set_prefix(sh,user, "user") + if status < 0: + raise Error("Could not set labeling prefix") + if self.verbose: print "User prefix set: ", semanage.semanage_user_get_prefix(user) + + status = semanage.semanage_user_set_mlsrange(sh, user, "s0") + if status < 0: + raise Error("Could not set MLS range") + if self.verbose: print "User mlsrange: ", semanage.semanage_user_get_mlsrange(user) + + status = semanage.semanage_user_set_mlslevel(sh, user, "s0") + if status < 0: + raise Error("Could not set MLS level") + if self.verbose: print "User mlslevel: ", semanage.semanage_user_get_mlslevel(user) + + (status,key) = semanage.semanage_user_key_extract(sh,user) + if status < 0: + raise Error("Could not extract user key") + if self.verbose: print "User key extracted: ", key + + (status,exists) = semanage.semanage_user_exists_local(sh,key) + if status < 0: + raise Error("Could not check if user exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_user) = semanage.semanage_user_query_local(sh, key) + if status < 0: + raise Error("Could not query old user") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction.." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_user_modify_local(sh,key,user) + if status < 0: + raise Error("Could not modify user") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing user..." + status = semanage.semanage_user_del_local(sh, key) + if status < 0: + raise Error("Could not delete test user") + if self.verbose: print "User delete: ", status + else: + print "Resetting user..." + status = semanage.semanage_user_modify_local(sh, key, old_user) + if status < 0: + raise Error("Could not reset test user") + if self.verbose: print "User modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_user_key_free(key) + semanage.semanage_user_free(user) + if exists: semanage.semanage_user_free(old_user) + + def test_writeseuser(self,sh): + print "Testing seuser write..." + + (status, seuser) = semanage.semanage_seuser_create(sh) + if status < 0: + raise Error("Could not create SEUser object") + if self.verbose: print "SEUser object created." + + status = semanage.semanage_seuser_set_name(sh,seuser, "testPySEUser") + if status < 0: + raise Error("Could not set name") + if self.verbose: print "SEUser name set: ", semanage.semanage_seuser_get_name(seuser) + + status = semanage.semanage_seuser_set_sename(sh, seuser, "root") + if status < 0: + raise Error("Could not set sename") + if self.verbose: print "SEUser seuser: ", semanage.semanage_seuser_get_sename(seuser) + + status = semanage.semanage_seuser_set_mlsrange(sh, seuser, "s0:c0.c255") + if status < 0: + raise Error("Could not set MLS range") + if self.verbose: print "SEUser mlsrange: ", semanage.semanage_seuser_get_mlsrange(seuser) + + (status,key) = semanage.semanage_seuser_key_extract(sh,seuser) + if status < 0: + raise Error("Could not extract SEUser key") + if self.verbose: print "SEUser key extracted: ", key + + (status,exists) = semanage.semanage_seuser_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SEUser exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_seuser) = semanage.semanage_seuser_query_local(sh, key) + if status < 0: + raise Error("Could not query old SEUser") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_seuser_modify_local(sh,key,seuser) + if status < 0: + raise Error("Could not modify SEUser") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing seuser..." + status = semanage.semanage_seuser_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SEUser") + if self.verbose: print "Seuser delete: ", status + else: + print "Resetting seuser..." + status = semanage.semanage_seuser_modify_local(sh, key, old_seuser) + if status < 0: + raise Error("Could not reset test SEUser") + if self.verbose: print "Seuser modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_seuser_key_free(key) + semanage.semanage_seuser_free(seuser) + if exists: semanage.semanage_seuser_free(old_seuser) + + def test_writeport(self,sh): + print "Testing port write..." + + (status, port) = semanage.semanage_port_create(sh) + if status < 0: + raise Error("Could not create SEPort object") + if self.verbose: print "SEPort object created." + + semanage.semanage_port_set_range(port,150,200) + low = semanage.semanage_port_get_low(port) + high = semanage.semanage_port_get_high(port) + if self.verbose: print "SEPort range set: ", low, "-", high + + semanage.semanage_port_set_proto(port, semanage.SEMANAGE_PROTO_TCP); + if self.verbose: print "SEPort protocol set: ", \ + semanage.semanage_port_get_proto_str(semanage.SEMANAGE_PROTO_TCP) + + (status, con) = semanage.semanage_context_create(sh) + if status < 0: + raise Error("Could not create SEContext object") + if self.verbose: print "SEContext object created (for port)." + + status = semanage.semanage_context_set_user(sh, con, "system_u") + if status < 0: + raise Error("Could not set context user") + if self.verbose: print "SEContext user: ", semanage.semanage_context_get_user(con) + + status = semanage.semanage_context_set_role(sh, con, "object_r") + if status < 0: + raise Error("Could not set context role") + if self.verbose: print "SEContext role: ", semanage.semanage_context_get_role(con) + + status = semanage.semanage_context_set_type(sh, con, "http_port_t") + if status < 0: + raise Error("Could not set context type") + if self.verbose: print "SEContext type: ", semanage.semanage_context_get_type(con) + + status = semanage.semanage_context_set_mls(sh, con, "s0:c0.c255") + if status < 0: + raise Error("Could not set context MLS fields") + if self.verbose: print "SEContext mls: ", semanage.semanage_context_get_mls(con) + + status = semanage.semanage_port_set_con(sh, port, con) + if status < 0: + raise Error("Could not set SEPort context") + if self.verbose: print "SEPort context set: ", con + + (status,key) = semanage.semanage_port_key_extract(sh,port) + if status < 0: + raise Error("Could not extract SEPort key") + if self.verbose: print "SEPort key extracted: ", key + + (status,exists) = semanage.semanage_port_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SEPort exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_port) = semanage.semanage_port_query_local(sh, key) + if status < 0: + raise Error("Could not query old SEPort") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_port_modify_local(sh,key,port) + if status < 0: + raise Error("Could not modify SEPort") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing port range..." + status = semanage.semanage_port_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SEPort") + if self.verbose: print "Port range delete: ", status + else: + print "Resetting port range..." + status = semanage.semanage_port_modify_local(sh, key, old_port) + if status < 0: + raise Error("Could not reset test SEPort") + if self.verbose: print "Port range modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_context_free(con) + semanage.semanage_port_key_free(key) + semanage.semanage_port_free(port) + if exists: semanage.semanage_port_free(old_port) + + def test_writefcontext(self,sh): + print "Testing file context write..." + + (status, fcon) = semanage.semanage_fcontext_create(sh) + if status < 0: + raise Error("Could not create SEFcontext object") + if self.verbose: print "SEFcontext object created." + + status = semanage.semanage_fcontext_set_expr(sh, fcon, "/test/fcontext(/.*)?") + if status < 0: + raise Error("Could not set expression") + if self.verbose: print "SEFContext expr set: ", semanage.semanage_fcontext_get_expr(fcon) + + semanage.semanage_fcontext_set_type(fcon, semanage.SEMANAGE_FCONTEXT_REG) + if self.verbose: + ftype = semanage.semanage_fcontext_get_type(fcon) + print "SEFContext type set: ", semanage.semanage_fcontext_get_type_str(ftype) + + (status, con) = semanage.semanage_context_create(sh) + if status < 0: + raise Error("Could not create SEContext object") + if self.verbose: print "SEContext object created (for file context)." + + status = semanage.semanage_context_set_user(sh, con, "system_u") + if status < 0: + raise Error("Could not set context user") + if self.verbose: print "SEContext user: ", semanage.semanage_context_get_user(con) + + status = semanage.semanage_context_set_role(sh, con, "object_r") + if status < 0: + raise Error("Could not set context role") + if self.verbose: print "SEContext role: ", semanage.semanage_context_get_role(con) + + status = semanage.semanage_context_set_type(sh, con, "default_t") + if status < 0: + raise Error("Could not set context type") + if self.verbose: print "SEContext type: ", semanage.semanage_context_get_type(con) + + status = semanage.semanage_context_set_mls(sh, con, "s0:c0.c255") + if status < 0: + raise Error("Could not set context MLS fields") + if self.verbose: print "SEContext mls: ", semanage.semanage_context_get_mls(con) + + status = semanage.semanage_fcontext_set_con(sh, fcon, con) + if status < 0: + raise Error("Could not set SEFcontext context") + if self.verbose: print "SEFcontext context set: ", con + + (status,key) = semanage.semanage_fcontext_key_extract(sh,fcon) + if status < 0: + raise Error("Could not extract SEFcontext key") + if self.verbose: print "SEFcontext key extracted: ", key + + (status,exists) = semanage.semanage_fcontext_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SEFcontext exists") + + if self.verbose: print "Exists status (commit number): ", status + if exists: + (status, old_fcontext) = semanage.semanage_fcontext_query_local(sh, key) + if status < 0: + raise Error("Could not query old SEFcontext") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_fcontext_modify_local(sh,key,fcon) + if status < 0: + raise Error("Could not modify SEFcontext") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing file context..." + status = semanage.semanage_fcontext_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SEFcontext") + if self.verbose: print "File context delete: ", status + else: + print "Resetting file context..." + status = semanage.semanage_fcontext_modify_local(sh, key, old_fcontext) + if status < 0: + raise Error("Could not reset test FContext") + if self.verbose: print "File context modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_context_free(con) + semanage.semanage_fcontext_key_free(key) + semanage.semanage_fcontext_free(fcon) + if exists: semanage.semanage_fcontext_free(old_fcontext) + + def test_writeinterface(self,sh): + print "Testing network interface write..." + + (status, iface) = semanage.semanage_iface_create(sh) + if status < 0: + raise Error("Could not create SEIface object") + if self.verbose: print "SEIface object created." + + status = semanage.semanage_iface_set_name(sh, iface, "test_iface") + if status < 0: + raise Error("Could not set SEIface name") + if self.verbose: print "SEIface name set: ", semanage.semanage_iface_get_name(iface) + + (status, con) = semanage.semanage_context_create(sh) + if status < 0: + raise Error("Could not create SEContext object") + if self.verbose: print "SEContext object created (for network interface)" + + status = semanage.semanage_context_set_user(sh, con, "system_u") + if status < 0: + raise Error("Could not set interface context user") + if self.verbose: print "SEContext user: ", semanage.semanage_context_get_user(con) + + status = semanage.semanage_context_set_role(sh, con, "object_r") + if status < 0: + raise Error("Could not set interface context role") + if self.verbose: print "SEContext role: ", semanage.semanage_context_get_role(con) + + status = semanage.semanage_context_set_type(sh, con, "default_t") + if status < 0: + raise Error("Could not set interface context type") + if self.verbose: print "SEContext type: ", semanage.semanage_context_get_type(con) + + status = semanage.semanage_context_set_mls(sh, con, "s0:c0.c255") + if status < 0: + raise Error("Could not set interface context MLS fields") + if self.verbose: print "SEContext mls: ", semanage.semanage_context_get_mls(con) + + status = semanage.semanage_iface_set_ifcon(sh, iface, con) + if status < 0: + raise Error("Could not set SEIface interface context") + if self.verbose: print "SEIface interface context set: ", con + + status = semanage.semanage_iface_set_msgcon(sh, iface, con) + if status < 0: + raise Error("Could not set SEIface message context") + if self.verbose: print "SEIface message context set: ", con + + (status,key) = semanage.semanage_iface_key_extract(sh,iface) + if status < 0: + raise Error("Could not extract SEIface key") + if self.verbose: print "SEIface key extracted: ", key + + (status,exists) = semanage.semanage_iface_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SEIface exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_iface) = semanage.semanage_iface_query_local(sh, key) + if status < 0: + raise Error("Could not query old SEIface") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not begin semanage transaction") + + status = semanage.semanage_iface_modify_local(sh,key,iface) + if status < 0: + raise Error("Could not modify SEIface") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not begin semanage transaction") + + if not exists: + print "Removing interface..." + status = semanage.semanage_iface_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SEIface") + if self.verbose: print "Interface delete: ", status + else: + print "Resetting interface..." + status = semanage.semanage_iface_modify_local(sh, key, old_iface) + if status < 0: + raise Error("Could not reset test SEIface") + if self.verbose: print "Interface modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_context_free(con) + semanage.semanage_iface_key_free(key) + semanage.semanage_iface_free(iface) + if exists: semanage.semanage_iface_free(old_iface) + + def test_writeboolean(self,sh): + print "Testing boolean write..." + + (status, pbool) = semanage.semanage_bool_create(sh) + if status < 0: + raise Error("Could not create SEBool object") + if self.verbose: print "SEBool object created." + + status = semanage.semanage_bool_set_name(sh, pbool, "allow_execmem") + if status < 0: + raise Error("Could not set name") + if self.verbose: print "SEBool name set: ", semanage.semanage_bool_get_name(pbool) + + semanage.semanage_bool_set_value(pbool, 0) + if self.verbose: print "SEbool value set: ", semanage.semanage_bool_get_value(pbool) + + (status,key) = semanage.semanage_bool_key_extract(sh, pbool) + if status < 0: + raise Error("Could not extract SEBool key") + if self.verbose: print "SEBool key extracted: ", key + + (status,exists) = semanage.semanage_bool_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SEBool exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_bool) = semanage.semanage_bool_query_local(sh, key) + if status < 0: + raise Error("Could not query old SEBool") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_bool_modify_local(sh, key, pbool) + + if status < 0: + raise Error("Could not modify SEBool") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing boolean..." + status = semanage.semanage_bool_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SEBool") + if self.verbose: print "Boolean delete: ", status + else: + print "Resetting boolean..." + status = semanage.semanage_bool_modify_local(sh, key, old_bool) + if status < 0: + raise Error("Could not reset test SEBool") + if self.verbose: print "Boolean modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_bool_key_free(key) + semanage.semanage_bool_free(pbool) + if exists: semanage.semanage_bool_free(old_bool) + + def test_writeaboolean(self,sh): + print "Testing active boolean write..." + + (status, key) = semanage.semanage_bool_key_create(sh, "allow_execmem") + if status < 0: + raise Error("Could not create SEBool key") + if self.verbose: print "SEBool key created: ", key + + (status, old_bool) = semanage.semanage_bool_query_active(sh, key) + if status < 0: + raise Error("Could not query old SEBool") + if self.verbose: print "Query status (commit number): ", status + + (status, abool) = semanage.semanage_bool_create(sh) + if status < 0: + raise Error("Could not create SEBool object") + if self.verbose: print "SEBool object created." + + status = semanage.semanage_bool_set_name(sh, abool, "allow_execmem") + if status < 0: + raise Error("Could not set name") + if self.verbose: print "SEBool name set: ", semanage.semanage_bool_get_name(abool) + + semanage.semanage_bool_set_value(abool, 0) + if self.verbose: print "SEbool value set: ", semanage.semanage_bool_get_value(abool) + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_bool_set_active(sh,key,abool) + if status < 0: + raise Error("Could not modify SEBool") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + print "Resetting old active boolean..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_bool_set_active(sh, key,old_bool) + if status < 0: + raise Error("Could not reset test SEBool") + if self.verbose: print "SEBool active reset: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_bool_key_free(key) + semanage.semanage_bool_free(abool) + semanage.semanage_bool_free(old_bool) + + + def test_writenode(self,sh): + print "Testing network node write..." + + (status, node) = semanage.semanage_node_create(sh) + if status < 0: + raise Error("Could not create SENode object") + if self.verbose: print "SENode object created." + + status = semanage.semanage_node_set_addr(sh, node, semanage.SEMANAGE_PROTO_IP6, "ffee:dddd::bbbb") + if status < 0: + raise Error("Could not set SENode address") + + status = semanage.semanage_node_set_mask(sh, node, semanage.SEMANAGE_PROTO_IP6, "::ffff:ffff:abcd:0000") + if status < 0: + raise Error("Could not set SENode netmask") + + semanage.semanage_node_set_proto(node, semanage.SEMANAGE_PROTO_IP6); + if self.verbose: print "SENode protocol set: ", \ + semanage.semanage_node_get_proto_str(semanage.SEMANAGE_PROTO_IP6) + + (status, con) = semanage.semanage_context_create(sh) + if status < 0: + raise Error("Could not create SEContext object") + if self.verbose: print "SEContext object created (for node)." + + status = semanage.semanage_context_set_user(sh, con, "system_u") + if status < 0: + raise Error("Could not set context user") + if self.verbose: print "SEContext user: ", semanage.semanage_context_get_user(con) + + status = semanage.semanage_context_set_role(sh, con, "object_r") + if status < 0: + raise Error("Could not set context role") + if self.verbose: print "SEContext role: ", semanage.semanage_context_get_role(con) + + status = semanage.semanage_context_set_type(sh, con, "lo_node_t") + if status < 0: + raise Error("Could not set context type") + if self.verbose: print "SEContext type: ", semanage.semanage_context_get_type(con) + + status = semanage.semanage_context_set_mls(sh, con, "s0:c0.c255") + if status < 0: + raise Error("Could not set context MLS fields") + if self.verbose: print "SEContext mls: ", semanage.semanage_context_get_mls(con) + + status = semanage.semanage_node_set_con(sh, node, con) + if status < 0: + raise Error("Could not set SENode context") + if self.verbose: print "SENode context set: ", con + + (status,key) = semanage.semanage_node_key_extract(sh, node) + if status < 0: + raise Error("Could not extract SENode key") + if self.verbose: print "SENode key extracted: ", key + + (status,exists) = semanage.semanage_node_exists_local(sh,key) + if status < 0: + raise Error("Could not check if SENode exists") + if self.verbose: print "Exists status (commit number): ", status + + if exists: + (status, old_node) = semanage.semanage_node_query_local(sh, key) + if status < 0: + raise Error("Could not query old SENode") + if self.verbose: print "Query status (commit number): ", status + + print "Starting transaction..." + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + status = semanage.semanage_node_modify_local(sh,key, node) + if status < 0: + raise Error("Could not modify SENode") + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit test transaction") + print "Commit status (transaction number): ", status + + status = semanage.semanage_begin_transaction(sh) + if status < 0: + raise Error("Could not start semanage transaction") + + if not exists: + print "Removing network node..." + status = semanage.semanage_node_del_local(sh, key) + if status < 0: + raise Error("Could not delete test SENode") + if self.verbose: print "Network node delete: ", status + else: + print "Resetting network node..." + status = semanage.semanage_node_modify_local(sh, key, old_node) + if status < 0: + raise Error("Could not reset test SENode") + if self.verbose: print "Network node modify: ", status + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print "Commit status (transaction number): ", status + + semanage.semanage_context_free(con) + semanage.semanage_node_key_free(key) + semanage.semanage_node_free(node) + if exists: semanage.semanage_node_free(old_node) + +def main(argv=None): + if argv is None: + argv = sys.argv + try: + try: + opts, args = getopt.getopt(argv[1:], "hvmuspfibcUSPFIBCanN", ["help", "verbose", "modules", "users", "seusers", "ports", "file contexts", "network interfaces", "booleans", "active booleans", "network nodes", "writeuser", "writeseuser", "writeport", "writefcontext", "writeinterface", "writeboolean", "writeaboolean", "writenode", "all"]) + tests = Tests() + for o, a in opts: + if o == "-v": + tests.verbose = True + print "Verbose output selected." + if o == "-a": + tests.all = True + if o == "-u": + tests.users = True + if o == "-U": + tests.writeuser = True + if o == "-s": + tests.seusers = True + if o == "-S": + tests.writeseuser = True + if o == "-p": + tests.ports = True + if o == "-P": + tests.writeport = True + if o == "-f": + tests.fcontexts = True + if o == "-F": + tests.writefcontext = True + if o == "-i": + tests.interfaces = True + if o == "-I": + tests.writeinterface = True + if o == "-b": + tests.booleans = True + if o == "-B": + tests.writeboolean = True + if o == "-c": + tests.abooleans = True + if o == "-C": + tests.writeaboolean = True + if o == "-n": + tests.nodes = True + if o == "-N": + tests.writenode = True + if o == "-m": + tests.modules = True + if o == "-h": + raise Usage(usage) + + if not tests.selected(): + raise Usage("Please select a valid test.") + + except getopt.error, msg: + raise Usage(msg) + + sh=semanage.semanage_handle_create() + + if (semanage.semanage_is_managed(sh) != 1): + raise Status("Unmanaged!") + + status = semanage.semanage_connect(sh) + if status < 0: + raise Error("Could not establish semanage connection") + + tests.run(sh) + + status = semanage.semanage_disconnect(sh) + if status < 0: + raise Error("Could not disconnect") + + semanage.semanage_handle_destroy(sh) + + except Usage, err: + print >>sys.stderr, err.msg + except Status, err: + print >>sys.stderr, err.msg + except Error, err: + print >>sys.stderr, err.msg + + return 2 + +if __name__ == "__main__": + sys.exit(main()) +
diff --git a/selinux/libsemanage/src/semanage.conf b/selinux/libsemanage/src/semanage.conf new file mode 100644 index 0000000..dc8d46b --- /dev/null +++ b/selinux/libsemanage/src/semanage.conf
@@ -0,0 +1,41 @@ +# Authors: Jason Tang <jtang@tresys.com> +# +# Copyright (C) 2004-2005 Tresys Technology, LLC +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# Specify how libsemanage will interact with a SELinux policy manager. +# The four options are: +# +# "source" - libsemanage manipulates a source SELinux policy +# "direct" - libsemanage will write directly to a module store. +# /foo/bar - Write by way of a policy management server, whose +# named socket is at /foo/bar. The path must begin +# with a '/'. +# foo.com:4242 - Establish a TCP connection to a remote policy +# management server at foo.com. If there is a colon +# then the remainder is interpreted as a port number; +# otherwise default to port 4242. +module-store = direct + +# When generating the final linked and expanded policy, by default +# semanage will set the policy version to POLICYDB_VERSION_MAX, as +# given in <sepol/policydb.h>. Change this setting if a different +# version is necessary. +#policy-version = 19 + +# By default, semanage will generate policies for the SELinux target. +# To build policies for Xen, uncomment the following line. +#target-platform = xen
diff --git a/selinux/libsemanage/src/semanage_conf.h b/selinux/libsemanage/src/semanage_conf.h new file mode 100644 index 0000000..c99ac8c --- /dev/null +++ b/selinux/libsemanage/src/semanage_conf.h
@@ -0,0 +1,70 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SEMANAGE_CONF_H +#define SEMANAGE_CONF_H + +#include <semanage/handle.h> +#include <sys/types.h> +#include <sys/stat.h> + +/* libsemanage has its own configuration file. It has two main parts: + * - single options + * - external programs to execute whenever a policy is to be loaded + */ + +typedef struct semanage_conf { + enum semanage_connect_type store_type; + char *store_path; /* used for both socket path and policy dir */ + char *compiler_directory_path; + int server_port; + int policyvers; /* version for server generated policies */ + int target_platform; + int expand_check; + int save_previous; + int save_linked; + int disable_genhomedircon; + int usepasswd; + int handle_unknown; + mode_t file_mode; + int bzip_blocksize; + int bzip_small; + int remove_hll; + int ignore_module_cache; + char *ignoredirs; /* ";" separated of list for genhomedircon to ignore */ + struct external_prog *load_policy; + struct external_prog *setfiles; + struct external_prog *sefcontext_compile; + struct external_prog *mod_prog, *linked_prog, *kernel_prog; + char *store_root_path; +} semanage_conf_t; + +/* A linked list of verification programs. Each one is called in + * order of appearance within the configuration file. + */ +typedef struct external_prog { + char *path; + char *args; + struct external_prog *next; +} external_prog_t; + +semanage_conf_t *semanage_conf_parse(const char *config_filename); +void semanage_conf_destroy(semanage_conf_t * conf); + +#endif
diff --git a/selinux/libsemanage/src/semanage_store.c b/selinux/libsemanage/src/semanage_store.c new file mode 100644 index 0000000..fa0876f --- /dev/null +++ b/selinux/libsemanage/src/semanage_store.c
@@ -0,0 +1,2917 @@ +/* Authors: Karl MacMillan <kmacmillan@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Christopher Ashworth <cashworth@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * Caleb Case <ccase@tresys.com> + * + * Copyright (C) 2004-2006,2009 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This file contains semanage routines that manipulate the files on a + * local module store. Sandbox routines, used by both source and + * direct connections, are here as well. + */ + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include "semanage_store.h" +#include "database_policydb.h" +#include "handle.h" + +#include <selinux/selinux.h> +#include <sepol/policydb.h> +#include <sepol/module.h> + +#include <assert.h> +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <limits.h> +#include <libgen.h> + +#include "debug.h" +#include "utilities.h" + +#define SEMANAGE_CONF_FILE "semanage.conf" +/* relative path names to enum semanage_paths to special files and + * directories for the module store */ + +#define TRUE 1 + +enum semanage_file_defs { + SEMANAGE_ROOT, + SEMANAGE_TRANS_LOCK, + SEMANAGE_READ_LOCK, + SEMANAGE_NUM_FILES +}; + +static char *semanage_paths[SEMANAGE_NUM_STORES][SEMANAGE_STORE_NUM_PATHS]; +static char *semanage_files[SEMANAGE_NUM_FILES] = { NULL }; +static int semanage_paths_initialized = 0; + +/* These are paths relative to the bottom of the module store */ +static const char *semanage_relative_files[SEMANAGE_NUM_FILES] = { + "", + "/semanage.trans.LOCK", + "/semanage.read.LOCK" +}; + +static const char *semanage_store_paths[SEMANAGE_NUM_STORES] = { + "/active", + "/previous", + "/tmp" +}; + +/* relative path names to enum sandbox_paths for special files within + * a sandbox */ +static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = { + "", + "/modules", + "/base.linked", + "/homedir_template", + "/file_contexts.template", + "/commit_num", + "/ports.local", + "/interfaces.local", + "/nodes.local", + "/booleans.local", + "/seusers.local", + "/users.local", + "/users_extra.local", + "/users_extra", + "/disable_dontaudit", + "/preserve_tunables", + "/modules/disabled", + "/policy.kern", + "/file_contexts.local", + "/file_contexts", + "/seusers" +}; + +static char const * const semanage_final_prefix[SEMANAGE_FINAL_NUM] = { + "/final", + "", +}; + +static char *semanage_final[SEMANAGE_FINAL_NUM] = { NULL }; +static char *semanage_final_suffix[SEMANAGE_FINAL_PATH_NUM] = { NULL }; +static char *semanage_final_paths[SEMANAGE_FINAL_NUM][SEMANAGE_FINAL_PATH_NUM] = {{ NULL }}; + +/* A node used in a linked list of file contexts; used for sorting. + */ +typedef struct semanage_file_context_node { + char *path; + char *file_type; + char *context; + int path_len; + int effective_len; + int type_len; + int context_len; + int meta; /* position of first meta char in path, -1 if none */ + struct semanage_file_context_node *next; +} semanage_file_context_node_t; + +/* A node used in a linked list of buckets that contain + * semanage_file_context_node lists. Used for sorting. + */ +typedef struct semanage_file_context_bucket { + semanage_file_context_node_t *data; + struct semanage_file_context_bucket *next; +} semanage_file_context_bucket_t; + +/* A node used in a linked list of netfilter rules. + */ +typedef struct semanage_netfilter_context_node { + char *rule; + size_t rule_len; + struct semanage_netfilter_context_node *next; +} semanage_netfilter_context_node_t; + +/* Initialize the paths to config file, lock files and store root. + */ +static int semanage_init_paths(const char *root) +{ + size_t len, prefix_len; + int i; + + if (!root) + return -1; + + prefix_len = strlen(root); + + for (i = 0; i < SEMANAGE_NUM_FILES; i++) { + len = (strlen(semanage_relative_files[i]) + prefix_len); + semanage_files[i] = calloc(len + 1, sizeof(char)); + if (!semanage_files[i]) + return -1; + sprintf(semanage_files[i], "%s%s", root, + semanage_relative_files[i]); + } + + return 0; +} + +/* This initializes the paths inside the stores, this is only necessary + * when directly accessing the store + */ +static int semanage_init_store_paths(const char *root) +{ + int i, j; + size_t len; + size_t prefix_len; + + if (!root) + return -1; + + prefix_len = strlen(root); + + for (i = 0; i < SEMANAGE_NUM_STORES; i++) { + for (j = 0; j < SEMANAGE_STORE_NUM_PATHS; j++) { + len = prefix_len + strlen(semanage_store_paths[i]) + + strlen(semanage_sandbox_paths[j]); + semanage_paths[i][j] = calloc(len + 1, sizeof(char)); + if (!semanage_paths[i][j]) + goto cleanup; + sprintf(semanage_paths[i][j], "%s%s%s", root, + semanage_store_paths[i], + semanage_sandbox_paths[j]); + } + } + + cleanup: + return 0; +} + +static int semanage_init_final(semanage_handle_t *sh, const char *prefix) +{ + assert(sh); + assert(prefix); + + int status = 0; + size_t len; + const char *store_path = sh->conf->store_path; + size_t store_len = strlen(store_path); + + /* SEMANAGE_FINAL_TMP */ + len = strlen(semanage_root()) + + strlen(prefix) + + strlen("/") + + strlen(semanage_final_prefix[SEMANAGE_FINAL_TMP]) + + store_len; + semanage_final[SEMANAGE_FINAL_TMP] = malloc(len + 1); + if (semanage_final[SEMANAGE_FINAL_TMP] == NULL) { + status = -1; + goto cleanup; + } + + sprintf(semanage_final[SEMANAGE_FINAL_TMP], + "%s%s%s/%s", + semanage_root(), + prefix, + semanage_final_prefix[SEMANAGE_FINAL_TMP], + store_path); + + /* SEMANAGE_FINAL_SELINUX */ + const char *selinux_root = selinux_path(); + len = strlen(semanage_root()) + + strlen(selinux_root) + + strlen(semanage_final_prefix[SEMANAGE_FINAL_SELINUX]) + + store_len; + semanage_final[SEMANAGE_FINAL_SELINUX] = malloc(len + 1); + if (semanage_final[SEMANAGE_FINAL_SELINUX] == NULL) { + status = -1; + goto cleanup; + } + + sprintf(semanage_final[SEMANAGE_FINAL_SELINUX], + "%s%s%s%s", + semanage_root(), + selinux_root, + semanage_final_prefix[SEMANAGE_FINAL_SELINUX], + store_path); + +cleanup: + if (status != 0) { + int i; + for (i = 0; i < SEMANAGE_FINAL_NUM; i++) { + free(semanage_final[i]); + semanage_final[i] = NULL; + } + } + + return status; +} + +static int semanage_init_final_suffix(semanage_handle_t *sh) +{ + int ret = 0; + int status = 0; + char path[PATH_MAX]; + size_t offset = strlen(selinux_policy_root()); + + semanage_final_suffix[SEMANAGE_FINAL_TOPLEVEL] = strdup(""); + if (semanage_final_suffix[SEMANAGE_FINAL_TOPLEVEL] == NULL) { + ERR(sh, "Unable to allocate space for policy top level path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_FC] = + strdup(selinux_file_context_path() + offset); + if (semanage_final_suffix[SEMANAGE_FC] == NULL) { + ERR(sh, "Unable to allocate space for file context path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] = + strdup(selinux_file_context_homedir_path() + offset); + if (semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] == NULL) { + ERR(sh, "Unable to allocate space for file context home directory path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_FC_LOCAL] = + strdup(selinux_file_context_local_path() + offset); + if (semanage_final_suffix[SEMANAGE_FC_LOCAL] == NULL) { + ERR(sh, "Unable to allocate space for local file context path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_NC] = + strdup(selinux_netfilter_context_path() + offset); + if (semanage_final_suffix[SEMANAGE_NC] == NULL) { + ERR(sh, "Unable to allocate space for netfilter context path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_SEUSERS] = + strdup(selinux_usersconf_path() + offset); + if (semanage_final_suffix[SEMANAGE_SEUSERS] == NULL) { + ERR(sh, "Unable to allocate space for userconf path."); + status = -1; + goto cleanup; + } + + ret = snprintf(path, + sizeof(path), + "%s.%d", + selinux_binary_policy_path() + offset, + sh->conf->policyvers); + if (ret < 0 || ret >= (int)sizeof(path)) { + ERR(sh, "Unable to compose policy binary path."); + status = -1; + goto cleanup; + } + + semanage_final_suffix[SEMANAGE_KERNEL] = strdup(path); + if (semanage_final_suffix[SEMANAGE_KERNEL] == NULL) { + ERR(sh, "Unable to allocate space for policy binary path."); + status = -1; + goto cleanup; + } + +cleanup: + if (status != 0) { + int i; + for (i = 0; i < SEMANAGE_FINAL_PATH_NUM; i++) { + free(semanage_final_suffix[i]); + semanage_final_suffix[i] = NULL; + } + } + + return status; +} + +/* Initialize final paths. */ +static int semanage_init_final_paths(semanage_handle_t *sh) +{ + int status = 0; + int i, j; + size_t len; + + for (i = 0; i < SEMANAGE_FINAL_NUM; i++) { + for (j = 0; j < SEMANAGE_FINAL_PATH_NUM; j++) { + len = strlen(semanage_final[i]) + + strlen(semanage_final_suffix[j]); + + semanage_final_paths[i][j] = malloc(len + 1); + if (semanage_final_paths[i][j] == NULL) { + ERR(sh, "Unable to allocate space for policy final path."); + status = -1; + goto cleanup; + } + + sprintf(semanage_final_paths[i][j], + "%s%s", + semanage_final[i], + semanage_final_suffix[j]); + } + } + +cleanup: + if (status != 0) { + for (i = 0; i < SEMANAGE_FINAL_NUM; i++) { + for (j = 0; j < SEMANAGE_FINAL_PATH_NUM; j++) { + free(semanage_final_paths[i][j]); + semanage_final_paths[i][j] = NULL; + } + } + } + + return status; +} + +/* THIS MUST BE THE FIRST FUNCTION CALLED IN THIS LIBRARY. If the + * library has nnot been initialized yet then call the functions that + * initialize the path variables. This function does nothing if it + * was previously called and that call was successful. Return 0 on + * success, -1 on error. + * + * Note that this function is NOT thread-safe. + */ +int semanage_check_init(semanage_handle_t *sh, const char *prefix) +{ + int rc; + if (semanage_paths_initialized == 0) { + char root[PATH_MAX]; + + rc = snprintf(root, + sizeof(root), + "%s%s/%s", + semanage_root(), + prefix, + sh->conf->store_path); + if (rc < 0 || rc >= (int)sizeof(root)) + return -1; + + rc = semanage_init_paths(root); + if (rc) + return rc; + + rc = semanage_init_store_paths(root); + if (rc) + return rc; + + rc = semanage_init_final(sh, prefix); + if (rc) + return rc; + + rc = semanage_init_final_suffix(sh); + if (rc) + return rc; + + rc = semanage_init_final_paths(sh); + if (rc) + return rc; + + semanage_paths_initialized = 1; + } + return 0; +} + +/* Given a definition number, return a file name from the paths array */ +const char *semanage_fname(enum semanage_sandbox_defs file_enum) +{ + return semanage_sandbox_paths[file_enum]; +} + +/* Given a store location (active/previous/tmp) and a definition + * number, return a fully-qualified path to that file or directory. + * The caller must not alter the string returned (and hence why this + * function return type is const). + * + * This function shall never return a NULL, assuming that + * semanage_check_init() was previously called. + */ +const char *semanage_path(enum semanage_store_defs store, + enum semanage_sandbox_defs path_name) +{ + assert(semanage_paths[store][path_name]); + return semanage_paths[store][path_name]; +} + +/* Given a store location (tmp or selinux) and a definition + * number, return a fully-qualified path to that file or directory. + * The caller must not alter the string returned (and hence why this + * function return type is const). + * + * This function shall never return a NULL, assuming that + * semanage_check_init() was previously called. + */ +const char *semanage_final_path(enum semanage_final_defs store, + enum semanage_final_path_defs path_name) +{ + assert(semanage_final_paths[store][path_name]); + return semanage_final_paths[store][path_name]; +} + +/* Return a fully-qualified path + filename to the semanage + * configuration file. If semanage.conf file in the semanage + * root is cannot be read, use the default semanage.conf as a + * fallback. + * + * The caller is responsible for freeing the returned string. + */ +char *semanage_conf_path(void) +{ + char *semanage_conf = NULL; + int len; + + len = strlen(semanage_root()) + strlen(selinux_path()) + strlen(SEMANAGE_CONF_FILE); + semanage_conf = calloc(len + 1, sizeof(char)); + if (!semanage_conf) + return NULL; + snprintf(semanage_conf, len + 1, "%s%s%s", semanage_root(), selinux_path(), + SEMANAGE_CONF_FILE); + + if (access(semanage_conf, R_OK) != 0) { + snprintf(semanage_conf, len + 1, "%s%s", selinux_path(), SEMANAGE_CONF_FILE); + } + + return semanage_conf; +} + +/**************** functions that create module store ***************/ + +/* Check that the semanage store exists. If 'create' is non-zero then + * create the directories. Returns 0 if module store exists (either + * already or just created), -1 if does not exist or could not be + * read, or -2 if it could not create the store. */ +int semanage_create_store(semanage_handle_t * sh, int create) +{ + struct stat sb; + int mode_mask = R_OK | W_OK | X_OK; + const char *path = semanage_files[SEMANAGE_ROOT]; + int fd; + + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + if (mkdir(path, S_IRWXU) == -1) { + ERR(sh, "Could not create module store at %s.", + path); + return -2; + } + } else { + if (create) + ERR(sh, + "Could not read from module store at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode) || access(path, mode_mask) == -1) { + ERR(sh, + "Could not access module store at %s, or it is not a directory.", + path); + return -1; + } + } + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL); + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + if (mkdir(path, S_IRWXU) == -1) { + ERR(sh, + "Could not create module store, active subdirectory at %s.", + path); + return -2; + } + } else { + ERR(sh, + "Could not read from module store, active subdirectory at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode) || access(path, mode_mask) == -1) { + ERR(sh, + "Could not access module store active subdirectory at %s, or it is not a directory.", + path); + return -1; + } + } + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + if (mkdir(path, S_IRWXU) == -1) { + ERR(sh, + "Could not create module store, active modules subdirectory at %s.", + path); + return -2; + } + } else { + ERR(sh, + "Could not read from module store, active modules subdirectory at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode) || access(path, mode_mask) == -1) { + ERR(sh, + "Could not access module store active modules subdirectory at %s, or it is not a directory.", + path); + return -1; + } + } + path = semanage_files[SEMANAGE_READ_LOCK]; + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + if ((fd = creat(path, S_IRUSR | S_IWUSR)) == -1) { + ERR(sh, "Could not create lock file at %s.", + path); + return -2; + } + close(fd); + } else { + ERR(sh, "Could not read lock file at %s.", path); + return -1; + } + } else { + if (!S_ISREG(sb.st_mode) || access(path, R_OK | W_OK) == -1) { + ERR(sh, "Could not access lock file at %s.", path); + return -1; + } + } + return 0; +} + +/* returns <0 if the active store cannot be read or doesn't exist + * 0 if the store exists but the lock file cannot be accessed + * SEMANAGE_CAN_READ if the store can be read and the lock file used + * SEMANAGE_CAN_WRITE if the modules directory and binary policy dir can be written to + */ +int semanage_store_access_check(void) +{ + const char *path; + int rc = -1; + + /* read access on active store */ + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL); + if (access(path, R_OK | X_OK) != 0) + goto out; + + /* we can read the active store meaning it is managed + * so now we return 0 to indicate no error */ + rc = 0; + + /* read access on lock file required for locking + * write access necessary if the lock file does not exist + */ + path = semanage_files[SEMANAGE_READ_LOCK]; + if (access(path, R_OK) != 0) { + if (access(path, F_OK) == 0) { + goto out; + } + + path = semanage_files[SEMANAGE_ROOT]; + if (access(path, R_OK | W_OK | X_OK) != 0) { + goto out; + } + } + + /* everything needed for reading has been checked */ + rc = SEMANAGE_CAN_READ; + + /* check the modules directory */ + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); + if (access(path, R_OK | W_OK | X_OK) != 0) + goto out; + + rc = SEMANAGE_CAN_WRITE; + + out: + return rc; +} + +/********************* other I/O functions *********************/ + +/* Callback used by scandir() to select files. */ +static int semanage_filename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + return 0; + return 1; +} + +/* Copies a file from src to dst. If dst already exists then + * overwrite it. Returns 0 on success, -1 on error. */ +int semanage_copy_file(const char *src, const char *dst, mode_t mode) +{ + int in, out, retval = 0, amount_read, n, errsv = errno; + char tmp[PATH_MAX]; + char buf[4192]; + mode_t mask; + + n = snprintf(tmp, PATH_MAX, "%s.tmp", dst); + if (n < 0 || n >= PATH_MAX) + return -1; + + if ((in = open(src, O_RDONLY)) == -1) { + return -1; + } + + if (!mode) + mode = S_IRUSR | S_IWUSR; + + mask = umask(0); + if ((out = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, mode)) == -1) { + umask(mask); + errsv = errno; + close(in); + retval = -1; + goto out; + } + umask(mask); + while (retval == 0 && (amount_read = read(in, buf, sizeof(buf))) > 0) { + if (write(out, buf, amount_read) < 0) { + errsv = errno; + retval = -1; + } + } + if (amount_read < 0) { + errsv = errno; + retval = -1; + } + close(in); + if (close(out) < 0) { + errsv = errno; + retval = -1; + } + + if (!retval && rename(tmp, dst) == -1) + return -1; + +out: + errno = errsv; + return retval; +} + +static int semanage_copy_dir_flags(const char *src, const char *dst, int flag); + +/* Copies all of the files from src to dst, recursing into + * subdirectories. Returns 0 on success, -1 on error. */ +static int semanage_copy_dir(const char *src, const char *dst) +{ + return semanage_copy_dir_flags(src, dst, 1); +} + +/* Copies all of the dirs from src to dst, recursing into + * subdirectories. If flag == 1, then copy regular files as + * well. Returns 0 on success, -1 on error. */ +static int semanage_copy_dir_flags(const char *src, const char *dst, int flag) +{ + int i, len = 0, retval = -1; + struct stat sb; + struct dirent **names = NULL; + char path[PATH_MAX], path2[PATH_MAX]; + + if ((len = scandir(src, &names, semanage_filename_select, NULL)) == -1) { + fprintf(stderr, "Could not read the contents of %s: %s\n", src, strerror(errno)); + return -1; + } + + if (stat(dst, &sb) != 0) { + if (mkdir(dst, S_IRWXU) != 0) { + fprintf(stderr, "Could not create %s: %s\n", dst, strerror(errno)); + goto cleanup; + } + } + + for (i = 0; i < len; i++) { + snprintf(path, sizeof(path), "%s/%s", src, names[i]->d_name); + /* stat() to see if this entry is a file or not since + * d_type isn't set properly on XFS */ + if (stat(path, &sb)) { + goto cleanup; + } + snprintf(path2, sizeof(path2), "%s/%s", dst, names[i]->d_name); + if (S_ISDIR(sb.st_mode)) { + if (mkdir(path2, 0700) == -1 || + semanage_copy_dir_flags(path, path2, flag) == -1) { + goto cleanup; + } + } else if (S_ISREG(sb.st_mode) && flag == 1) { + if (semanage_copy_file(path, path2, sb.st_mode) < 0) { + goto cleanup; + } + } + } + retval = 0; + cleanup: + for (i = 0; names != NULL && i < len; i++) { + free(names[i]); + } + free(names); + return retval; +} + +/* Recursively removes the contents of a directory along with the + * directory itself. Returns 0 on success, non-zero on error. */ +int semanage_remove_directory(const char *path) +{ + struct dirent **namelist = NULL; + int num_entries, i; + if ((num_entries = scandir(path, &namelist, semanage_filename_select, + NULL)) == -1) { + return -1; + } + for (i = 0; i < num_entries; i++) { + char s[NAME_MAX]; + struct stat buf; + snprintf(s, sizeof(s), "%s/%s", path, namelist[i]->d_name); + if (stat(s, &buf) == -1) { + return -2; + } + if (S_ISDIR(buf.st_mode)) { + int retval; + if ((retval = semanage_remove_directory(s)) != 0) { + return retval; + } + } else { + if (remove(s) == -1) { + return -3; + } + } + free(namelist[i]); + } + free(namelist); + if (rmdir(path) == -1) { + return -4; + } + return 0; +} + +int semanage_mkpath(semanage_handle_t *sh, const char *path) +{ + char fn[PATH_MAX]; + char *c; + int rc = 0; + + if (strlen(path) >= PATH_MAX) { + return -1; + } + + for (c = strcpy(fn, path) + 1; *c != '\0'; c++) { + if (*c != '/') { + continue; + } + + *c = '\0'; + rc = semanage_mkdir(sh, fn); + if (rc < 0) { + goto cleanup; + } + *c = '/'; + } + rc = semanage_mkdir(sh, fn); + +cleanup: + return rc; +} + +int semanage_mkdir(semanage_handle_t *sh, const char *path) +{ + int status = 0; + struct stat sb; + + /* check if directory already exists */ + if (stat(path, &sb) != 0) { + /* make the modules directory */ + if (mkdir(path, S_IRWXU) != 0) { + ERR(sh, "Cannot make directory at %s", path); + status = -1; + goto cleanup; + + } + } + else { + /* check that it really is a directory */ + if (!S_ISDIR(sb.st_mode)) { + ERR(sh, "Directory path taken by non-directory file at %s.", path); + status = -1; + goto cleanup; + } + } + +cleanup: + return status; +} + +/********************* sandbox management routines *********************/ + +/* Creates a sandbox for a single client. Returns 0 if a + * sandbox was created, -1 on error. + */ +int semanage_make_sandbox(semanage_handle_t * sh) +{ + const char *sandbox = semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL); + struct stat buf; + int errsv; + + if (stat(sandbox, &buf) == -1) { + if (errno != ENOENT) { + ERR(sh, "Error scanning directory %s.", sandbox); + return -1; + } + errno = 0; + } else { + /* remove the old sandbox */ + if (semanage_remove_directory(sandbox) != 0) { + ERR(sh, "Error removing old sandbox directory %s.", + sandbox); + return -1; + } + } + + if (mkdir(sandbox, S_IRWXU) == -1 || + semanage_copy_dir(semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL), + sandbox) == -1) { + ERR(sh, "Could not copy files to sandbox %s.", sandbox); + goto cleanup; + } + return 0; + + cleanup: + errsv = errno; + semanage_remove_directory(sandbox); + errno = errsv; + return -1; +} + +/* Create final temporary space. Returns -1 on error 0 on success. */ +int semanage_make_final(semanage_handle_t *sh) +{ + int status = 0; + int ret = 0; + char fn[PATH_MAX]; + + /* Create tmp dir if it does not exist. */ + ret = snprintf(fn, + sizeof(fn), + "%s%s%s", + semanage_root(), + sh->conf->store_root_path, + semanage_final_prefix[SEMANAGE_FINAL_TMP]); + if (ret < 0 || ret >= (int)sizeof(fn)) { + ERR(sh, "Unable to compose the final tmp path."); + status = -1; + goto cleanup; + } + + ret = semanage_mkdir(sh, fn); + if (ret != 0) { + ERR(sh, "Unable to create temporary directory for final files at %s", fn); + status = -1; + goto cleanup; + } + + /* Delete store specific dir if it exists. */ + ret = semanage_remove_directory( + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)); + if (ret < -1) { + status = -1; + goto cleanup; + } + + // Build final directory structure + int i; + for (i = 1; i < SEMANAGE_FINAL_PATH_NUM; i++) { + if (strlen(semanage_final_path(SEMANAGE_FINAL_TMP, i)) >= sizeof(fn)) { + ERR(sh, "Unable to compose the final paths."); + status = -1; + goto cleanup; + } + strcpy(fn, semanage_final_path(SEMANAGE_FINAL_TMP, i)); + ret = semanage_mkpath(sh, dirname(fn)); + if (ret < 0) { + status = -1; + goto cleanup; + } + } + +cleanup: + return status; +} + +/* qsort comparison function for semanage_get_active_modules. */ +static int semanage_get_active_modules_cmp(const void *a, const void *b) +{ + semanage_module_info_t *aa = (semanage_module_info_t *)a; + semanage_module_info_t *bb = (semanage_module_info_t *)b; + + return strcmp(aa->name, bb->name); +} + +int semanage_get_cil_paths(semanage_handle_t * sh, + semanage_module_info_t *modinfos, + int num_modinfos, + char *** filenames) +{ + char path[PATH_MAX]; + char **names = NULL; + + int ret; + int status = 0; + int i = 0; + + names = calloc(num_modinfos, sizeof(*names)); + if (names == NULL) { + ERR(sh, "Error allocating space for filenames."); + status = -1; + goto cleanup; + } + + for (i = 0; i < num_modinfos; i++) { + ret = semanage_module_get_path( + sh, + &modinfos[i], + SEMANAGE_MODULE_PATH_CIL, + path, + sizeof(path)); + if (ret != 0) { + status = -1; + goto cleanup; + } + + names[i] = strdup(path); + + if (names[i] == NULL) { + status = -1; + goto cleanup; + } + } + +cleanup: + if (status != 0) { + for (i = 0; i < num_modinfos; i++) { + free(names[i]); + } + free(names); + } else { + *filenames = names; + } + + return status; +} + +/* Scans the modules directory for the current semanage handler. This + * might be the active directory or sandbox, depending upon if the + * handler has a transaction lock. Allocates and fills in *modinfos + * with an array of module infos; length of array is stored in + * *num_modules. The caller is responsible for free()ing *modinfos and its + * individual elements. Upon success returns 0, -1 on error. + */ +int semanage_get_active_modules(semanage_handle_t * sh, + semanage_module_info_t ** modinfo, + int *num_modules) +{ + assert(sh); + assert(modinfo); + assert(num_modules); + *modinfo = NULL; + *num_modules = 0; + + int status = 0; + int ret = 0; + + int i = 0; + int j = 0; + + semanage_list_t *list = NULL; + semanage_list_t *found = NULL; + + semanage_module_info_t *all_modinfos = NULL; + int all_modinfos_len = 0; + + void *tmp = NULL; + + /* get all modules */ + ret = semanage_module_list_all(sh, &all_modinfos, &all_modinfos_len); + if (ret != 0) { + status = -1; + goto cleanup; + } + + if (all_modinfos_len == 0) { + goto cleanup; + } + + /* allocate enough for worst case */ + (*modinfo) = calloc(all_modinfos_len, sizeof(**modinfo)); + if ((*modinfo) == NULL) { + ERR(sh, "Error allocating space for module information."); + status = -1; + goto cleanup; + } + + /* for each highest priority, enabled module get its path */ + semanage_list_destroy(&list); + j = 0; + for (i = 0; i < all_modinfos_len; i++) { + /* check if enabled */ + if (all_modinfos[i].enabled != 1) continue; + + /* check if we've seen this before (i.e. highest priority) */ + found = semanage_list_find(list, all_modinfos[i].name); + if (found == NULL) { + ret = semanage_list_push(&list, all_modinfos[i].name); + if (ret != 0) { + ERR(sh, "Failed to add module name to list of known names."); + status = -1; + goto cleanup; + } + } + else continue; + + if (semanage_module_info_clone(sh, &all_modinfos[i], &(*modinfo)[j]) != 0) { + status = -1; + goto cleanup; + } + + j += 1; + } + + *num_modules = j; + + if (j == 0) { + free(*modinfo); + *modinfo = NULL; + goto cleanup; + } + + /* realloc the array to its min size */ + tmp = realloc(*modinfo, j * sizeof(**modinfo)); + if (tmp == NULL) { + ERR(sh, "Error allocating space for filenames."); + status = -1; + goto cleanup; + } + *modinfo = tmp; + + /* sort array on module name */ + qsort(*modinfo, + *num_modules, + sizeof(**modinfo), + semanage_get_active_modules_cmp); + +cleanup: + semanage_list_destroy(&list); + + for (i = 0; i < all_modinfos_len; i++) { + semanage_module_info_destroy(sh, &all_modinfos[i]); + } + free(all_modinfos); + + if (status != 0) { + for (i = 0; i < j; j++) { + semanage_module_info_destroy(sh, &(*modinfo)[i]); + } + free(*modinfo); + } + + return status; +} + +/******************* routines that run external programs *******************/ + +/* Appends a single character to a string. Returns a pointer to the + * realloc()ated string. If out of memory return NULL; original + * string will remain untouched. + */ +static char *append(char *s, char c) +{ + size_t len = (s == NULL ? 0 : strlen(s)); + char *new_s = realloc(s, len + 2); + if (new_s == NULL) { + return NULL; + } + s = new_s; + s[len] = c; + s[len + 1] = '\0'; + return s; +} + +/* Append string 't' to string 's', realloc()ating 's' as needed. 't' + * may be safely free()d afterwards. Returns a pointer to the + * realloc()ated 's'. If out of memory return NULL; original strings + * will remain untouched. + */ +static char *append_str(char *s, const char *t) +{ + size_t s_len = (s == NULL ? 0 : strlen(s)); + size_t t_len = (t == NULL ? 0 : strlen(t)); + char *new_s = realloc(s, s_len + t_len + 1); + if (new_s == NULL) { + return NULL; + } + s = new_s; + memcpy(s + s_len, t, t_len); + s[s_len + t_len] = '\0'; + return s; +} + +/* + * Append an argument string to an argument vector. Replaces the + * argument pointer passed in. Returns -1 on error. Increments + * 'num_args' on success. + */ +static int append_arg(char ***argv, int *num_args, const char *arg) +{ + char **a; + + a = realloc(*argv, sizeof(**argv) * (*num_args + 1)); + if (a == NULL) + return -1; + + *argv = a; + a[*num_args] = NULL; + + if (arg) { + a[*num_args] = strdup(arg); + if (!a[*num_args]) + return -1; + } + (*num_args)++; + return 0; +} + +/* free()s all strings within a null-terminated argument vector, as + * well as the pointer itself. */ +static void free_argv(char **argv) +{ + int i; + for (i = 0; argv != NULL && argv[i] != NULL; i++) { + free(argv[i]); + } + free(argv); +} + +/* Take an argument string and split and place into an argument + * vector. Respect normal quoting, double-quoting, and backslash + * conventions. Perform substitutions on $@ and $< symbols. Returns + * a NULL-terminated argument vector; caller is responsible for + * free()ing the vector and its elements. */ +static char **split_args(const char *arg0, char *arg_string, + const char *new_name, const char *old_name) +{ + char **argv = NULL, *s, *arg = NULL, *targ; + int num_args = 0, in_quote = 0, in_dquote = 0, rc; + + rc = append_arg(&argv, &num_args, arg0); + if (rc) + goto cleanup; + s = arg_string; + /* parse the argument string one character at a time, + * repsecting quotes and other special characters */ + while (s != NULL && *s != '\0') { + switch (*s) { + case '\\':{ + if (*(s + 1) == '\0') { + targ = append(arg, '\\'); + if (targ == NULL) + goto cleanup; + arg = targ; + } else { + targ = append(arg, *(s + 1)); + if (targ == NULL) + goto cleanup; + arg = targ; + s++; + } + break; + } + case '\'':{ + if (in_dquote) { + targ = append(arg, *s); + if (targ == NULL) + goto cleanup; + arg = targ; + } else if (in_quote) { + in_quote = 0; + } else { + in_quote = 1; + targ = append(arg, '\0'); + if (targ == NULL) + goto cleanup; + arg = targ; + } + break; + } + case '\"':{ + if (in_quote) { + targ = append(arg, *s); + if (targ == NULL) + goto cleanup; + arg = targ; + } else if (in_dquote) { + in_dquote = 0; + } else { + in_dquote = 1; + targ = append(arg, '\0'); + if (targ == NULL) + goto cleanup; + arg = targ; + } + break; + } + case '$':{ + switch (*(s + 1)) { + case '@':{ + targ = append_str(arg, new_name); + if (targ == NULL) + goto cleanup; + arg = targ; + s++; + break; + } + case '<':{ + targ = append_str(arg, old_name); + if (targ == NULL) + goto cleanup; + arg = targ; + s++; + break; + } + default:{ + targ = append(arg, *s); + if (targ == NULL) + goto cleanup; + arg = targ; + } + } + break; + } + default:{ + if (isspace(*s) && !in_quote && !in_dquote) { + if (arg != NULL) { + rc = append_arg(&argv, &num_args, arg); + free(arg); + arg = NULL; + } + } else { + if ((targ = append(arg, *s)) == NULL) { + goto cleanup; + } else { + arg = targ; + } + } + } + } + s++; + } + if (arg != NULL) { + rc = append_arg(&argv, &num_args, arg); + free(arg); + arg = NULL; + } + /* explicitly add a NULL at the end */ + rc = append_arg(&argv, &num_args, NULL); + if (rc) + goto cleanup; + return argv; + cleanup: + free_argv(argv); + free(arg); + return NULL; +} + +/* Take the arguments given in v->args and expand any $ macros within. + * Split the arguments into different strings (argv). Next fork and + * execute the process. BE SURE THAT ALL FILE DESCRIPTORS ARE SET TO + * CLOSE-ON-EXEC. Take the return value of the child process and + * return it, -1 on error. + */ +static int semanage_exec_prog(semanage_handle_t * sh, + external_prog_t * e, const char *new_name, + const char *old_name) +{ + char **argv; + pid_t forkval; + int status = 0; + + argv = split_args(e->path, e->args, new_name, old_name); + if (argv == NULL) { + ERR(sh, "Out of memory!"); + return -1; + } + + /* no need to use pthread_atfork() -- child will not be using + * any mutexes. */ + forkval = vfork(); + if (forkval == 0) { + /* child process. file descriptors will be closed + * because they were set as close-on-exec. */ + execve(e->path, argv, NULL); + _exit(EXIT_FAILURE); /* if execve() failed */ + } + + free_argv(argv); + + if (forkval == -1) { + ERR(sh, "Error while forking process."); + return -1; + } + + /* parent process. wait for child to finish */ + if (waitpid(forkval, &status, 0) == -1 || !WIFEXITED(status)) { + ERR(sh, "Child process %s did not exit cleanly.", + e->path); + return -1; + } + return WEXITSTATUS(status); +} + +/* reloads the policy pointed to by the handle, used locally by install + * and exported for user reload requests */ +int semanage_reload_policy(semanage_handle_t * sh) +{ + int r = 0; + + if (!sh) + return -1; + + if ((r = semanage_exec_prog(sh, sh->conf->load_policy, "", "")) != 0) { + ERR(sh, "load_policy returned error code %d.", r); + } + return r; +} + +hidden_def(semanage_reload_policy) + +/* This expands the file_context.tmpl file to file_context and homedirs.template */ +int semanage_split_fc(semanage_handle_t * sh) +{ + FILE *file_con = NULL; + int fc = -1, hd = -1, retval = -1; + char buf[PATH_MAX] = { 0 }; + + /* I use fopen here instead of open so that I can use fgets which only reads a single line */ + file_con = fopen(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL), "r"); + if (!file_con) { + ERR(sh, "Could not open %s for reading.", + semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL)); + goto cleanup; + } + + fc = open(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), + O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fc < 0) { + ERR(sh, "Could not open %s for writing.", + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC)); + goto cleanup; + } + hd = open(semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL), + O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (hd < 0) { + ERR(sh, "Could not open %s for writing.", + semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL)); + goto cleanup; + } + + while (fgets_unlocked(buf, PATH_MAX, file_con)) { + if (!strncmp(buf, "HOME_DIR", 8) || + !strncmp(buf, "HOME_ROOT", 9) || strstr(buf, "ROLE") || + strstr(buf, "USER")) { + /* This contains one of the template variables, write it to homedir.template */ + if (write(hd, buf, strlen(buf)) < 0) { + ERR(sh, "Write to %s failed.", + semanage_path(SEMANAGE_TMP, + SEMANAGE_HOMEDIR_TMPL)); + goto cleanup; + } + } else { + if (write(fc, buf, strlen(buf)) < 0) { + ERR(sh, "Write to %s failed.", + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC)); + goto cleanup; + } + } + } + + retval = 0; + cleanup: + if (file_con) + fclose(file_con); + if (fc >= 0) + close(fc); + if (hd >= 0) + close(hd); + + return retval; + +} + +static int sefcontext_compile(semanage_handle_t * sh, const char *path) { + + int r; + + if (access(path, F_OK) != 0) { + return 0; + } + + if ((r = semanage_exec_prog(sh, sh->conf->sefcontext_compile, path, "")) != 0) { + ERR(sh, "sefcontext_compile returned error code %d. Compiling %s", r, path); + return -1; + } + + return 0; +} + +/* Load the contexts of the final tmp into the final selinux directory. + * Return 0 on success, -3 on error. + */ +static int semanage_install_final_tmp(semanage_handle_t * sh) +{ + int status = -3; + int ret = 0; + int i = 0; + const char *src = NULL; + const char *dst = NULL; + struct stat sb; + char fn[PATH_MAX]; + + /* For each of the final files install it if it exists. + * i = 1 to avoid copying the top level directory. + */ + for (i = 1; i < SEMANAGE_FINAL_PATH_NUM; i++) { + src = semanage_final_path(SEMANAGE_FINAL_TMP, i); + dst = semanage_final_path(SEMANAGE_FINAL_SELINUX, i); + + /* skip file if src doesn't exist */ + if (stat(src, &sb) != 0) continue; + + /* skip genhomedircon if configured */ + if (sh->conf->disable_genhomedircon && + i == SEMANAGE_FC_HOMEDIRS) continue; + + strcpy(fn, dst); + ret = semanage_mkpath(sh, dirname(fn)); + if (ret < 0) { + goto cleanup; + } + + ret = semanage_copy_file(src, dst, sh->conf->file_mode); + if (ret < 0) { + ERR(sh, "Could not copy %s to %s.", src, dst); + goto cleanup; + } + } + + if (!sh->do_reload) + goto skip_reload; + + /* This stats what libselinux says the active store is (according to config) + * and what we are installing to, to decide if they are the same store. If + * they are not then we do not reload policy. + */ + const char *really_active_store = selinux_policy_root(); + struct stat astore; + struct stat istore; + const char *storepath = semanage_final_path(SEMANAGE_FINAL_SELINUX, + SEMANAGE_FINAL_TOPLEVEL); + + if (stat(really_active_store, &astore) == 0) { + if (stat(storepath, &istore)) { + ERR(sh, "Could not stat store path %s.", storepath); + goto cleanup; + } + + if (!(astore.st_ino == istore.st_ino && + astore.st_dev == istore.st_dev)) { + /* They are not the same store */ + goto skip_reload; + } + } else if (errno == ENOENT && + strcmp(really_active_store, storepath) != 0) { + errno = 0; + goto skip_reload; + } + + if (semanage_reload_policy(sh)) { + goto cleanup; + } + +skip_reload: + if (sh->do_check_contexts) { + ret = semanage_exec_prog( + sh, + sh->conf->setfiles, + semanage_final_path(SEMANAGE_FINAL_SELINUX, + SEMANAGE_KERNEL), + semanage_final_path(SEMANAGE_FINAL_SELINUX, + SEMANAGE_FC)); + if (ret != 0) { + ERR(sh, "setfiles returned error code %d.", ret); + goto cleanup; + } + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_LOCAL)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_HOMEDIRS)) != 0) { + goto cleanup; + } + + status = 0; +cleanup: + return status; +} + +/* Prepare the sandbox to be installed by making a backup of the + * current active directory. Then copy the sandbox to the active + * directory. Return the new commit number on success, negative + * values on error. */ +static int semanage_commit_sandbox(semanage_handle_t * sh) +{ + int commit_number, fd, retval; + char write_buf[32]; + const char *commit_filename = + semanage_path(SEMANAGE_TMP, SEMANAGE_COMMIT_NUM_FILE); + ssize_t amount_written; + const char *active = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL); + const char *backup = + semanage_path(SEMANAGE_PREVIOUS, SEMANAGE_TOPLEVEL); + const char *sandbox = semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL); + struct stat buf; + + /* update the commit number */ + if ((commit_number = semanage_direct_get_serial(sh)) < 0) { + return -1; + } + commit_number++; + memset(write_buf, 0, sizeof(write_buf)); + snprintf(write_buf, sizeof(write_buf), "%d", commit_number); + if ((fd = + open(commit_filename, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR)) == -1) { + ERR(sh, "Could not open commit number file %s for writing.", + commit_filename); + return -1; + } + amount_written = write(fd, write_buf, sizeof(write_buf)); + if (amount_written == -1) { + ERR(sh, "Error while writing commit number to %s.", + commit_filename); + close(fd); + return -1; + } + close(fd); + + retval = commit_number; + + if (semanage_get_active_lock(sh) < 0) { + return -1; + } + /* make the backup of the current active directory */ + if (stat(backup, &buf) == 0) { + if (S_ISDIR(buf.st_mode) && + semanage_remove_directory(backup) != 0) { + ERR(sh, "Could not remove previous backup %s.", backup); + retval = -1; + goto cleanup; + } + } else if (errno != ENOENT) { + ERR(sh, "Could not stat directory %s.", backup); + retval = -1; + goto cleanup; + } + + if (rename(active, backup) == -1) { + ERR(sh, "Error while renaming %s to %s.", active, backup); + retval = -1; + goto cleanup; + } + + /* clean up some files from the sandbox before install */ + /* remove homedir_template from sandbox */ + + if (rename(sandbox, active) == -1) { + ERR(sh, "Error while renaming %s to %s.", sandbox, active); + /* note that if an error occurs during the next + * function then the store will be left in an + * inconsistent state */ + if (rename(backup, active) < 0) + ERR(sh, "Error while renaming %s back to %s.", backup, + active); + retval = -1; + goto cleanup; + } + if (semanage_install_final_tmp(sh) != 0) { + /* note that if an error occurs during the next three + * function then the store will be left in an + * inconsistent state */ + int errsv = errno; + if (rename(active, sandbox) < 0) + ERR(sh, "Error while renaming %s back to %s.", active, + sandbox); + else if (rename(backup, active) < 0) + ERR(sh, "Error while renaming %s back to %s.", backup, + active); + else + semanage_install_final_tmp(sh); + errno = errsv; + retval = -1; + goto cleanup; + } + + if (!sh->conf->save_previous) { + int errsv = errno; + retval = semanage_remove_directory(backup); + if (retval < 0) { + ERR(sh, "Could not delete previous directory %s.", backup); + goto cleanup; + } + errno = errsv; + } + + cleanup: + semanage_release_active_lock(sh); + return retval; +} + +/* Takes the kernel policy in a sandbox, move it to the active + * directory, copy it to the binary policy path, then load it. Upon + * error move the active directory back to the sandbox. This function + * should be placed within a mutex lock to ensure that it runs + * atomically. Returns commit number on success, -1 on error. + */ +int semanage_install_sandbox(semanage_handle_t * sh) +{ + int retval = -1, commit_num = -1; + + if (sh->conf->load_policy == NULL) { + ERR(sh, + "No load_policy program specified in configuration file."); + goto cleanup; + } + if (sh->conf->setfiles == NULL) { + ERR(sh, "No setfiles program specified in configuration file."); + goto cleanup; + } + + if (sh->conf->sefcontext_compile == NULL) { + ERR(sh, "No sefcontext_compile program specified in configuration file."); + goto cleanup; + } + + if ((commit_num = semanage_commit_sandbox(sh)) < 0) { + retval = commit_num; + goto cleanup; + } + + retval = commit_num; + + cleanup: + return retval; + +} + +/********************* functions that manipulate lock *********************/ + +static int semanage_get_lock(semanage_handle_t * sh, + const char *lock_name, const char *lock_file) +{ + int fd; + struct timeval origtime, curtime; + int got_lock = 0; + + if ((fd = open(lock_file, O_RDONLY)) == -1) { + if ((fd = + open(lock_file, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR)) == -1) { + ERR(sh, "Could not open direct %s at %s.", lock_name, + lock_file); + return -1; + } + } + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + ERR(sh, "Could not set close-on-exec for %s at %s.", lock_name, + lock_file); + close(fd); + return -1; + } + + if (sh->timeout == 0) { + /* return immediately */ + origtime.tv_sec = 0; + } else { + origtime.tv_sec = sh->timeout; + } + origtime.tv_usec = 0; + do { + curtime.tv_sec = 1; + curtime.tv_usec = 0; + if (flock(fd, LOCK_EX | LOCK_NB) == 0) { + got_lock = 1; + break; + } else if (errno != EAGAIN) { + ERR(sh, "Error obtaining direct %s at %s.", lock_name, + lock_file); + close(fd); + return -1; + } + if (origtime.tv_sec > 0 || sh->timeout == -1) { + if (select(0, NULL, NULL, NULL, &curtime) == -1) { + if (errno == EINTR) { + continue; + } + ERR(sh, + "Error while waiting to get direct %s at %s.", + lock_name, lock_file); + close(fd); + return -1; + } + origtime.tv_sec--; + } + } while (origtime.tv_sec > 0 || sh->timeout == -1); + if (!got_lock) { + ERR(sh, "Could not get direct %s at %s.", lock_name, lock_file); + close(fd); + return -1; + } + return fd; +} + +/* Locking for the module store for transactions. This is very basic + * locking of the module store and doesn't do anything if the module + * store is being manipulated with a program not using this library + * (but the policy should prevent that). Returns 0 on success, -1 if + * it could not obtain a lock. + */ +int semanage_get_trans_lock(semanage_handle_t * sh) +{ + const char *lock_file = semanage_files[SEMANAGE_TRANS_LOCK]; + + if (sh->u.direct.translock_file_fd >= 0) + return 0; + + sh->u.direct.translock_file_fd = + semanage_get_lock(sh, "transaction lock", lock_file); + if (sh->u.direct.translock_file_fd >= 0) { + return 0; + } else { + return -1; + } +} + +/* Locking for the module store for active store reading; this also includes + * the file containing the commit number. This is very basic locking + * of the module store and doesn't do anything if the module store is + * being manipulated with a program not using this library (but the + * policy should prevent that). Returns 0 on success, -1 if it could + * not obtain a lock. + */ +int semanage_get_active_lock(semanage_handle_t * sh) +{ + const char *lock_file = semanage_files[SEMANAGE_READ_LOCK]; + + if (sh->u.direct.activelock_file_fd >= 0) + return 0; + + sh->u.direct.activelock_file_fd = + semanage_get_lock(sh, "read lock", lock_file); + if (sh->u.direct.activelock_file_fd >= 0) { + return 0; + } else { + return -1; + } +} + +/* Releases the transaction lock. Does nothing if there was not one already + * there. */ +void semanage_release_trans_lock(semanage_handle_t * sh) +{ + int errsv = errno; + if (sh->u.direct.translock_file_fd >= 0) { + flock(sh->u.direct.translock_file_fd, LOCK_UN); + close(sh->u.direct.translock_file_fd); + sh->u.direct.translock_file_fd = -1; + } + errno = errsv; +} + +/* Releases the read lock. Does nothing if there was not one already + * there. */ +void semanage_release_active_lock(semanage_handle_t * sh) +{ + int errsv = errno; + if (sh->u.direct.activelock_file_fd >= 0) { + flock(sh->u.direct.activelock_file_fd, LOCK_UN); + close(sh->u.direct.activelock_file_fd); + sh->u.direct.activelock_file_fd = -1; + } + errno = errsv; +} + +/* Read the current commit number from the commit number file which + * the handle is pointing, resetting the file pointer afterwards. + * Return it (a non-negative number), or -1 on error. */ +int semanage_direct_get_serial(semanage_handle_t * sh) +{ + char buf[32]; + int fd, commit_number; + ssize_t amount_read; + const char *commit_filename; + memset(buf, 0, sizeof(buf)); + + if (sh->is_in_transaction) { + commit_filename = + semanage_path(SEMANAGE_TMP, SEMANAGE_COMMIT_NUM_FILE); + } else { + commit_filename = + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_COMMIT_NUM_FILE); + } + + if ((fd = open(commit_filename, O_RDONLY)) == -1) { + if (errno == ENOENT) { + /* the commit number file does not exist yet, + * so assume that the number is 0 */ + errno = 0; + return 0; + } else { + ERR(sh, "Could not open commit number file %s.", + commit_filename); + return -1; + } + } + + amount_read = read(fd, buf, sizeof(buf)); + if (amount_read == -1) { + ERR(sh, "Error while reading commit number from %s.", + commit_filename); + commit_number = -1; + } else if (sscanf(buf, "%d", &commit_number) != 1) { + /* if nothing was read, assume that the commit number is 0 */ + commit_number = 0; + } else if (commit_number < 0) { + /* read file ought never have negative values */ + ERR(sh, + "Commit number file %s is corrupted; it should only contain a non-negative integer.", + commit_filename); + commit_number = -1; + } + + close(fd); + return commit_number; +} + +/* HIGHER LEVEL COMMIT FUNCTIONS */ + +int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filenames, int numfiles) +{ + int retval = 0; + FILE *fp; + ssize_t size; + char *data = NULL; + char *filename; + int i; + + for (i = 0; i < numfiles; i++) { + filename = filenames[i]; + + if ((fp = fopen(filename, "rb")) == NULL) { + ERR(sh, "Could not open module file %s for reading.", filename); + goto cleanup; + } + + if ((size = bunzip(sh, fp, &data)) <= 0) { + rewind(fp); + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fseek(fp, 0, SEEK_END) != 0) { + ERR(sh, "Failed to determine size of file %s.", filename); + goto cleanup; + } + size = ftell(fp); + rewind(fp); + + data = malloc(size); + if (fread(data, size, 1, fp) != 1) { + ERR(sh, "Failed to read file %s.", filename); + goto cleanup; + } + } + + fclose(fp); + fp = NULL; + + retval = cil_add_file(cildb, filename, data, size); + if (retval != SEPOL_OK) { + ERR(sh, "Error while reading from file %s.", filename); + goto cleanup; + } + + free(data); + data = NULL; + } + + return retval; + + cleanup: + if (fp != NULL) { + fclose(fp); + } + free(data); + return -1; +} + +/* + * Expands the policy contained within *base + */ + +/** + * Read the policy from the sandbox (kernel) + */ +int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in) +{ + + int retval = STATUS_ERR; + const char *kernel_filename = NULL; + struct sepol_policy_file *pf = NULL; + FILE *infile = NULL; + + if ((kernel_filename = + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL)) == NULL) { + goto cleanup; + } + if ((infile = fopen(kernel_filename, "r")) == NULL) { + ERR(sh, "Could not open kernel policy %s for reading.", + kernel_filename); + goto cleanup; + } + __fsetlocking(infile, FSETLOCKING_BYCALLER); + if (sepol_policy_file_create(&pf)) { + ERR(sh, "Out of memory!"); + goto cleanup; + } + sepol_policy_file_set_fp(pf, infile); + sepol_policy_file_set_handle(pf, sh->sepolh); + if (sepol_policydb_read(in, pf) == -1) { + ERR(sh, "Error while reading kernel policy from %s.", + kernel_filename); + goto cleanup; + } + retval = STATUS_SUCCESS; + + cleanup: + if (infile != NULL) { + fclose(infile); + } + sepol_policy_file_free(pf); + return retval; +} +/** + * Writes the final policy to the sandbox (kernel) + */ +int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out) +{ + + int retval = STATUS_ERR; + const char *kernel_filename = NULL; + struct sepol_policy_file *pf = NULL; + FILE *outfile = NULL; + + if ((kernel_filename = + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL)) == NULL) { + goto cleanup; + } + if ((outfile = fopen(kernel_filename, "wb")) == NULL) { + ERR(sh, "Could not open kernel policy %s for writing.", + kernel_filename); + goto cleanup; + } + __fsetlocking(outfile, FSETLOCKING_BYCALLER); + if (sepol_policy_file_create(&pf)) { + ERR(sh, "Out of memory!"); + goto cleanup; + } + sepol_policy_file_set_fp(pf, outfile); + sepol_policy_file_set_handle(pf, sh->sepolh); + if (sepol_policydb_write(out, pf) == -1) { + ERR(sh, "Error while writing kernel policy to %s.", + kernel_filename); + goto cleanup; + } + retval = STATUS_SUCCESS; + + cleanup: + if (outfile != NULL) { + fclose(outfile); + } + sepol_policy_file_free(pf); + return retval; +} + +/* Execute the module verification programs for each source module. + * Returns 0 if every verifier returned success, -1 on error. + */ +int semanage_verify_modules(semanage_handle_t * sh, + char **module_filenames, int num_modules) +{ + int i, retval; + semanage_conf_t *conf = sh->conf; + if (conf->mod_prog == NULL) { + return 0; + } + for (i = 0; i < num_modules; i++) { + char *module = module_filenames[i]; + external_prog_t *e; + for (e = conf->mod_prog; e != NULL; e = e->next) { + if ((retval = + semanage_exec_prog(sh, e, module, "$<")) != 0) { + return -1; + } + } + } + return 0; +} + +/* Execute the linker verification programs for the linked (but not + * expanded) base. Returns 0 if every verifier returned success, -1 + * on error. + */ +int semanage_verify_linked(semanage_handle_t * sh) +{ + external_prog_t *e; + semanage_conf_t *conf = sh->conf; + const char *linked_filename = + semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED); + int retval = -1; + if (conf->linked_prog == NULL) { + return 0; + } + for (e = conf->linked_prog; e != NULL; e = e->next) { + if (semanage_exec_prog(sh, e, linked_filename, "$<") != 0) { + goto cleanup; + } + } + retval = 0; + cleanup: + return retval; +} + +/* Execute each of the kernel verification programs. Returns 0 if + * every verifier returned success, -1 on error. + */ +int semanage_verify_kernel(semanage_handle_t * sh) +{ + int retval = -1; + const char *kernel_filename = + semanage_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL); + semanage_conf_t *conf = sh->conf; + external_prog_t *e; + if (conf->kernel_prog == NULL) { + return 0; + } + for (e = conf->kernel_prog; e != NULL; e = e->next) { + if (semanage_exec_prog(sh, e, kernel_filename, "$<") != 0) { + goto cleanup; + } + } + retval = 0; + cleanup: + return retval; +} + +/********************* functions that sort file contexts *********************/ + +/* Free the given node. */ +static void semanage_fc_node_destroy(semanage_file_context_node_t * x) +{ + free(x->path); + free(x->file_type); + free(x->context); + free(x); +} + +/* Free the linked list of nodes starting at the given node. */ +static void semanage_fc_node_list_destroy(semanage_file_context_node_t * x) +{ + semanage_file_context_node_t *temp; + + while (x) { + temp = x; + x = x->next; + semanage_fc_node_destroy(temp); + } +} + +/* Free the linked list of buckets (and their node lists) + * starting at the given bucket. */ +static void semanage_fc_bucket_list_destroy(semanage_file_context_bucket_t * x) +{ + semanage_file_context_bucket_t *temp; + + while (x) { + temp = x; + x = x->next; + semanage_fc_node_list_destroy(temp->data); + free(temp); + } +} + +/* Compares two file contexts' regular expressions and returns: + * -1 if a is less specific than b + * 0 if a and be are equally specific + * 1 if a is more specific than b + * The comparison is based on the following heuristics, + * in order from most important to least important, given a and b: + * If a is a regular expression and b is not, + * -> a is less specific than b. + * If a's stem length is shorter than b's stem length, + * -> a is less specific than b. + * If a's string length is shorter than b's string length, + * -> a is less specific than b. + * If a does not have a specified type and b does not, + * -> a is less specific than b. + * FIXME: These heuristics are imperfect, but good enough for + * now. A proper comparison would determine which (if either) + * regular expression is a subset of the other. + */ +static int semanage_fc_compare(semanage_file_context_node_t * a, + semanage_file_context_node_t * b) +{ + int a_has_meta = (a->meta >= 0); + int b_has_meta = (b->meta >= 0); + + /* Check to see if either a or b are regexes + * and the other isn't. */ + if (a_has_meta && !b_has_meta) + return -1; + if (b_has_meta && !a_has_meta) + return 1; + + /* Check to see if either a or b have a shorter stem + * length than the other. */ + if (a->meta < b->meta) + return -1; + if (b->meta < a->meta) + return 1; + + /* Check to see if either a or b have a shorter string + * length than the other. */ + if (a->effective_len < b->effective_len) + return -1; + if (b->effective_len < a->effective_len) + return 1; + + /* Check to see if either a or b has a specified type + * and the other doesn't. */ + if (!a->file_type && b->file_type) + return -1; + if (!b->file_type && a->file_type) + return 1; + + /* If none of the above conditions were satisfied, + * then a and b are equally specific. */ + return 0; +} + +/* Merges two sorted file context linked lists into a single sorted one. + * The left list is assumed to represent nodes that came first in the original ordering. + * The final sorted list is returned. + */ +static semanage_file_context_node_t + * semanage_fc_merge(semanage_file_context_node_t * left, + semanage_file_context_node_t * right) +{ + semanage_file_context_node_t *head; + semanage_file_context_node_t *current; + semanage_file_context_node_t *tail; + + if (!left) + return right; + + if (!right) + return left; + + if (semanage_fc_compare(left, right) == 1) { + head = tail = right; + right = right->next; + } else { + head = tail = left; + left = left->next; + } + + while (left && right) { + /* if left was more specific than right, + * insert right before left. Otherwise leave order alone. */ + if (semanage_fc_compare(left, right) == 1) { + current = right; + right = right->next; + } else { + current = left; + left = left->next; + } + + tail = tail->next = current; + } + + tail->next = (left != NULL) ? left : right; + + return head; +} + +/* Sorts file contexts from least specific to most specific. + * A bucket linked list is passed in. Upon completion, + * there is only one bucket (pointed to by master) that + * contains a linked list of all the file contexts in sorted order. + * Explanation of the algorithm: + * This is a stable implementation of an iterative merge sort. + * Each bucket initially has a linked list of file contexts + * that are 1 node long. + * Each pass, buckets (and the nodes they contain) are merged + * two at time. + * Buckets are merged until there is only one bucket left, + * containing the list of file contexts, sorted. + */ +static void semanage_fc_merge_sort(semanage_file_context_bucket_t * master) +{ + semanage_file_context_bucket_t *current; + semanage_file_context_bucket_t *temp; + + /* Loop until master is the only bucket left. + * When we stop master contains the sorted list. */ + while (master->next) { + current = master; + + /* Merge buckets two-by-two. + * If there is an odd number of buckets, the last + * bucket will be left alone, which corresponds + * to the operation of merging it with an empty bucket. */ + while (current) { + if (current->next) { + current->data = + semanage_fc_merge(current->data, + current->next->data); + temp = current->next; + current->next = current->next->next; + + /* Free the (now empty) second bucket. + * (This does not touch the node list + * in the bucket because it has been + * shifted over to the first bucket. */ + free(temp); + } + current = current->next; + } + } +} + +/* Compute the location of the first regular expression + * meta character in the path of the given node, if it exists. + * On return: + * fc_node->meta = position of meta character, if it exists + * (-1 corresponds to no character) + */ +static void semanage_fc_find_meta(semanage_file_context_node_t * fc_node) +{ + int c = 0; + int escape_chars = 0; + + fc_node->meta = -1; + + /* Note: this while loop has been adapted from + * spec_hasMetaChars in matchpathcon.c from + * libselinux-1.22. */ + while (fc_node->path[c] != '\0') { + switch (fc_node->path[c]) { + case '.': + case '^': + case '$': + case '?': + case '*': + case '+': + case '|': + case '[': + case '(': + case '{': + fc_node->meta = c - escape_chars; + return; + case '\\': + /* If an escape character is found, + * skip the next character. */ + c++; + escape_chars++; + break; + } + + c++; + } +} + +/* Replicates strchr, but limits search to buf_len characters. */ +static char *semanage_strnchr(const char *buf, size_t buf_len, char c) +{ + size_t idx = 0; + + if (buf == NULL) + return NULL; + if (buf_len <= 0) + return NULL; + + while (idx < buf_len) { + if (buf[idx] == c) + return (char *)buf + idx; + idx++; + } + + return NULL; +} + +/* Returns a pointer to the end of line character in the given buffer. + * Used in the context of a file context char buffer that we will be + * parsing and sorting. + */ +static char *semanage_get_line_end(const char *buf, size_t buf_len) +{ + char *line_end = NULL; + + if (buf == NULL) + return NULL; + if (buf_len <= 0) + return NULL; + + line_end = semanage_strnchr(buf, buf_len, '\n'); + if (!line_end) + line_end = semanage_strnchr(buf, buf_len, '\r'); + if (!line_end) + line_end = semanage_strnchr(buf, buf_len, EOF); + + return line_end; +} + +/* Entry function for sorting a set of file context lines. + * Returns 0 on success, -1 on failure. + * Allocates a buffer pointed to by sorted_buf that contains the sorted lines. + * sorted_buf_len is set to the size of this buffer. + * This buffer is guaranteed to have a final \0 character. + * This buffer must be released by the caller. + */ +int semanage_fc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len, + char **sorted_buf, size_t * sorted_buf_len) +{ + size_t start, finish, regex_len, type_len, context_len; + size_t line_len, buf_remainder, i; + ssize_t sanity_check; + const char *line_buf, *line_end; + char *sorted_buf_pos; + int escape_chars, just_saw_escape; + + semanage_file_context_node_t *temp; + semanage_file_context_node_t *head; + semanage_file_context_node_t *current; + semanage_file_context_bucket_t *master; + semanage_file_context_bucket_t *bcurrent; + + i = 0; + + if (sh == NULL) { + return -1; + } + if (buf == NULL) { + ERR(sh, "Received NULL buffer."); + return -1; + } + if (buf_len <= 0) { + ERR(sh, "Received buffer of length 0."); + return -1; + } + + /* Initialize the head of the linked list + * that will contain a node for each file context line. */ + head = current = + (semanage_file_context_node_t *) calloc(1, + sizeof + (semanage_file_context_node_t)); + if (!head) { + ERR(sh, "Failure allocating memory."); + return -1; + } + + /* Parse the char buffer into a semanage_file_context_node_t linked list. */ + line_buf = buf; + buf_remainder = buf_len; + while ((line_end = semanage_get_line_end(line_buf, buf_remainder))) { + line_len = line_end - line_buf + 1; + sanity_check = buf_remainder - line_len; + buf_remainder = buf_remainder - line_len; + + if (sanity_check < 0) { + ERR(sh, "Failure parsing file context buffer."); + semanage_fc_node_list_destroy(head); + return -1; + } + + if (line_len == 0 || line_len == 1) { + line_buf = line_end + 1; + continue; + } + + /* Skip the whitespace at the front of the line. */ + for (i = 0; i < line_len; i++) { + if (!isspace(line_buf[i])) + break; + } + + /* Check for a blank line. */ + if (i >= line_len) { + line_buf = line_end + 1; + continue; + } + + /* Check if the line is a comment. */ + if (line_buf[i] == '#') { + line_buf = line_end + 1; + continue; + } + + /* Allocate a new node. */ + temp = + (semanage_file_context_node_t *) calloc(1, + sizeof + (semanage_file_context_node_t)); + if (!temp) { + ERR(sh, "Failure allocating memory."); + semanage_fc_node_list_destroy(head); + return -1; + } + temp->next = NULL; + + /* Extract the regular expression from the line. */ + escape_chars = 0; + just_saw_escape = 0; + start = i; + while (i < line_len && (!isspace(line_buf[i]))) { + if (line_buf[i] == '\\') { + if (!just_saw_escape) { + escape_chars++; + just_saw_escape = 1; + } else { + /* We're looking at an escaped + escape. Reset our flag. */ + just_saw_escape = 0; + } + } else { + just_saw_escape = 0; + } + i++; + } + finish = i; + regex_len = finish - start; + + if (regex_len == 0) { + ERR(sh, + "WARNING: semanage_fc_sort: Regex of length 0."); + semanage_fc_node_destroy(temp); + line_buf = line_end + 1; + continue; + } + + temp->path = (char *)strndup(&line_buf[start], regex_len); + if (!temp->path) { + ERR(sh, "Failure allocating memory."); + semanage_fc_node_destroy(temp); + semanage_fc_node_list_destroy(head); + return -1; + } + + /* Skip the whitespace after the regular expression. */ + for (; i < line_len; i++) { + if (!isspace(line_buf[i])) + break; + } + if (i == line_len) { + ERR(sh, + "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path); + semanage_fc_node_destroy(temp); + line_buf = line_end + 1; + continue; + } + + /* Extract the inode type from the line (if it exists). */ + if (line_buf[i] == '-') { + type_len = 2; /* defined as '--', '-d', '-f', etc. */ + + if (i + type_len >= line_len) { + ERR(sh, + "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path); + semanage_fc_node_destroy(temp); + line_buf = line_end + 1; + continue; + } + + /* Record the inode type. */ + temp->file_type = + (char *)strndup(&line_buf[i], type_len); + if (!temp->file_type) { + ERR(sh, "Failure allocating memory."); + semanage_fc_node_destroy(temp); + semanage_fc_node_list_destroy(head); + return -1; + } + + i += type_len; + + /* Skip the whitespace after the type. */ + for (; i < line_len; i++) { + if (!isspace(line_buf[i])) + break; + } + if (i == line_len) { + ERR(sh, + "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path); + semanage_fc_node_destroy(temp); + line_buf = line_end + 1; + continue; + } + } else { + type_len = 0; /* inode type did not exist in the file context */ + } + + /* Extract the context from the line. */ + start = i; + while (i < line_len && (!isspace(line_buf[i]))) + i++; + finish = i; + context_len = finish - start; + + temp->context = (char *)strndup(&line_buf[start], context_len); + if (!temp->context) { + ERR(sh, "Failure allocating memory."); + semanage_fc_node_destroy(temp); + semanage_fc_node_list_destroy(head); + return -1; + } + + /* Initialize the data about the file context. */ + temp->path_len = regex_len; + temp->effective_len = regex_len - escape_chars; + temp->type_len = type_len; + temp->context_len = context_len; + semanage_fc_find_meta(temp); + + /* Add this node to the end of the linked list. */ + current->next = temp; + current = current->next; + + line_buf = line_end + 1; + } + + /* Create the bucket linked list from the node linked list. */ + current = head->next; + bcurrent = master = (semanage_file_context_bucket_t *) + calloc(1, sizeof(semanage_file_context_bucket_t)); + if (!master) { + ERR(sh, "Failure allocating memory."); + semanage_fc_node_list_destroy(head); + return -1; + } + + /* Free the head node, as it is no longer used. */ + semanage_fc_node_destroy(head); + head = NULL; + + /* Place each node into a bucket. */ + while (current) { + bcurrent->data = current; + current = current->next; + + /* Detach the node in the bucket from the old list. */ + bcurrent->data->next = NULL; + + /* If we need another bucket, add one to the end. */ + if (current) { + bcurrent->next = (semanage_file_context_bucket_t *) + calloc(1, sizeof(semanage_file_context_bucket_t)); + if (!(bcurrent->next)) { + ERR(sh, "Failure allocating memory."); + semanage_fc_bucket_list_destroy(master); + return -1; + } + + bcurrent = bcurrent->next; + } + } + + /* Sort the bucket list. */ + semanage_fc_merge_sort(master); + + /* First, calculate how much space we'll need for + * the newly sorted block of data. (We don't just + * use buf_len for this because we have extracted + * comments and whitespace.) */ + i = 0; + current = master->data; + while (current) { + i += current->path_len + 1; /* +1 for a tab */ + if (current->file_type) { + i += current->type_len + 1; /* +1 for a tab */ + } + i += current->context_len + 1; /* +1 for a newline */ + current = current->next; + } + i = i + 1; /* +1 for trailing \0 */ + + /* Allocate the buffer for the sorted list. */ + *sorted_buf = calloc(i, sizeof(char)); + if (!*sorted_buf) { + ERR(sh, "Failure allocating memory."); + semanage_fc_bucket_list_destroy(master); + return -1; + } + *sorted_buf_len = i; + + /* Output the sorted semanage_file_context linked list to the char buffer. */ + sorted_buf_pos = *sorted_buf; + current = master->data; + while (current) { + /* Output the path. */ + i = current->path_len + 1; /* +1 for tab */ + snprintf(sorted_buf_pos, i + 1, "%s\t", current->path); + sorted_buf_pos = sorted_buf_pos + i; + + /* Output the type, if there is one. */ + if (current->file_type) { + i = strlen(current->file_type) + 1; /* +1 for tab */ + snprintf(sorted_buf_pos, i + 1, "%s\t", + current->file_type); + sorted_buf_pos = sorted_buf_pos + i; + } + + /* Output the context. */ + i = strlen(current->context) + 1; /* +1 for newline */ + snprintf(sorted_buf_pos, i + 1, "%s\n", current->context); + sorted_buf_pos = sorted_buf_pos + i; + + current = current->next; + } + + /* Clean up. */ + semanage_fc_bucket_list_destroy(master); + + /* Sanity check. */ + sorted_buf_pos++; + if ((sorted_buf_pos - *sorted_buf) != (ssize_t) * sorted_buf_len) { + ERR(sh, "Failure writing sorted buffer."); + free(*sorted_buf); + *sorted_buf = NULL; + return -1; + } + + return 0; +} + +/********************* functions that sort netfilter contexts *********************/ +#define NC_SORT_NAMES { "pre", "base", "module", "local", "post" } +#define NC_SORT_NAMES_LEN { 3, 4, 6, 5, 4 } +#define NC_SORT_NEL 5 +static void semanage_nc_destroy_ruletab(semanage_netfilter_context_node_t * + ruletab[NC_SORT_NEL][2]) +{ + semanage_netfilter_context_node_t *curr, *next; + int i; + + for (i = 0; i < NC_SORT_NEL; i++) { + for (curr = ruletab[i][0]; curr != NULL; curr = next) { + next = curr->next; + free(curr->rule); + free(curr); + } + } +} + +/* Entry function for sorting a set of netfilter context lines. + * Returns 0 on success, -1 on failure. + * Allocates a buffer pointed to by sorted_buf that contains the sorted lines. + * sorted_buf_len is set to the size of this buffer. + * This buffer is guaranteed to have a final \0 character. + * This buffer must be released by the caller. + */ +int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len, + char **sorted_buf, size_t * sorted_buf_len) +{ + + /* parsing bits */ + const char *priority_names[] = NC_SORT_NAMES; + const int priority_names_len[] = NC_SORT_NAMES_LEN; + size_t line_len, buf_remainder, i, offset; + const char *line_buf, *line_end; + + /* ruletab bits */ + /* keep track of the head (index 0) and tail (index 1) with this array */ + semanage_netfilter_context_node_t *ruletab[NC_SORT_NEL][2]; + semanage_netfilter_context_node_t *curr, *node; + int priority; + + /* sorted buffer bits */ + char *sorted_buf_pos; + size_t count; + + /* initialize ruletab */ + memset(ruletab, 0, + NC_SORT_NEL * 2 * sizeof(semanage_netfilter_context_node_t *)); + + /* while lines to be read */ + line_buf = buf; + buf_remainder = buf_len; + while ((line_end = semanage_get_line_end(line_buf, buf_remainder))) { + line_len = line_end - line_buf + 1; + buf_remainder = buf_remainder - line_len; + + if (line_len == 0 || line_len == 1) { + line_buf = line_end + 1; + continue; + } + + /* Skip the whitespace at the front of the line. */ + for (i = 0; i < line_len; i++) { + if (!isspace(line_buf[i])) + break; + } + + /* Check for a blank line. */ + if (i >= line_len) { + line_buf = line_end + 1; + continue; + } + + /* Check if the line is a comment. */ + if (line_buf[i] == '#') { + line_buf = line_end + 1; + continue; + } + + /* extract priority */ + priority = -1; + offset = 0; + for (i = 0; i < NC_SORT_NEL; i++) { + if (strncmp + (line_buf, priority_names[i], + priority_names_len[i]) == 0) { + priority = i; + offset = priority_names_len[i]; + break; + } + } + + if (priority < 0) { + ERR(sh, "Netfilter context line missing priority."); + semanage_nc_destroy_ruletab(ruletab); + return -1; + } + + /* skip over whitespace */ + for (; offset < line_len && isspace(line_buf[offset]); + offset++) ; + + /* load rule into node */ + node = (semanage_netfilter_context_node_t *) + malloc(sizeof(semanage_netfilter_context_node_t)); + if (!node) { + ERR(sh, "Failure allocating memory."); + semanage_nc_destroy_ruletab(ruletab); + return -1; + } + + node->rule = + (char *)strndup(line_buf + offset, line_len - offset); + node->rule_len = line_len - offset; + node->next = NULL; + + if (!node->rule) { + ERR(sh, "Failure allocating memory."); + free(node); + semanage_nc_destroy_ruletab(ruletab); + return -1; + } + + /* add node to rule table */ + if (ruletab[priority][0] && ruletab[priority][1]) { + /* add to end of list, update tail pointer */ + ruletab[priority][1]->next = node; + ruletab[priority][1] = node; + } else { + /* this list is empty, make head and tail point to the node */ + ruletab[priority][0] = ruletab[priority][1] = node; + } + + line_buf = line_end + 1; + } + + /* First, calculate how much space we'll need for + * the newly sorted block of data. (We don't just + * use buf_len for this because we have extracted + * comments and whitespace.) Start at 1 for trailing \0 */ + count = 1; + for (i = 0; i < NC_SORT_NEL; i++) + for (curr = ruletab[i][0]; curr != NULL; curr = curr->next) + count += curr->rule_len; + + /* Allocate the buffer for the sorted list. */ + *sorted_buf = calloc(count, sizeof(char)); + if (!*sorted_buf) { + ERR(sh, "Failure allocating memory."); + semanage_nc_destroy_ruletab(ruletab); + return -1; + } + *sorted_buf_len = count; + + /* write out rule buffer */ + sorted_buf_pos = *sorted_buf; + for (i = 0; i < NC_SORT_NEL; i++) { + for (curr = ruletab[i][0]; curr != NULL; curr = curr->next) { + /* put rule into buffer */ + snprintf(sorted_buf_pos, curr->rule_len + 1, "%s\n", curr->rule); /* +1 for newline */ + sorted_buf_pos = sorted_buf_pos + curr->rule_len; + } + } + + /* free ruletab */ + semanage_nc_destroy_ruletab(ruletab); + + return 0; +}
diff --git a/selinux/libsemanage/src/semanage_store.h b/selinux/libsemanage/src/semanage_store.h new file mode 100644 index 0000000..acb6e3f --- /dev/null +++ b/selinux/libsemanage/src/semanage_store.h
@@ -0,0 +1,157 @@ +/* Authors: Karl MacMillan <kmacmillan@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * Christopher Ashworth <cashworth@tresys.com> + * + * Copyright (C) 2004-2006 Tresys Technology, LLC + * Copyright (C) 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SEMANAGE_MODULE_STORE_H +#define SEMANAGE_MODULE_STORE_H + +#include <sys/time.h> +#include <sepol/module.h> +#include <sepol/cil/cil.h> +#include "handle.h" + +enum semanage_store_defs { + SEMANAGE_ACTIVE, + SEMANAGE_PREVIOUS, + SEMANAGE_TMP, + SEMANAGE_NUM_STORES +}; + +/* sandbox filenames and paths */ +enum semanage_sandbox_defs { + SEMANAGE_TOPLEVEL, + SEMANAGE_MODULES, + SEMANAGE_LINKED, + SEMANAGE_HOMEDIR_TMPL, + SEMANAGE_FC_TMPL, + SEMANAGE_COMMIT_NUM_FILE, + SEMANAGE_PORTS_LOCAL, + SEMANAGE_INTERFACES_LOCAL, + SEMANAGE_NODES_LOCAL, + SEMANAGE_BOOLEANS_LOCAL, + SEMANAGE_SEUSERS_LOCAL, + SEMANAGE_USERS_BASE_LOCAL, + SEMANAGE_USERS_EXTRA_LOCAL, + SEMANAGE_USERS_EXTRA, + SEMANAGE_DISABLE_DONTAUDIT, + SEMANAGE_PRESERVE_TUNABLES, + SEMANAGE_MODULES_DISABLED, + SEMANAGE_STORE_KERNEL, + SEMANAGE_STORE_FC_LOCAL, + SEMANAGE_STORE_FC, + SEMANAGE_STORE_SEUSERS, + SEMANAGE_STORE_NUM_PATHS +}; + +enum semanage_final_defs { + SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_SELINUX, + SEMANAGE_FINAL_NUM +}; + +enum semanage_final_path_defs { + SEMANAGE_FINAL_TOPLEVEL, + SEMANAGE_FC, + SEMANAGE_FC_HOMEDIRS, + SEMANAGE_FC_LOCAL, + SEMANAGE_KERNEL, + SEMANAGE_NC, + SEMANAGE_SEUSERS, + SEMANAGE_FINAL_PATH_NUM +}; + +/* FIXME: this needs to be made a module store specific init and the + * global configuration moved to another file. + */ +char *semanage_conf_path(void); + +int semanage_check_init(semanage_handle_t *sh, const char *prefix); + +extern const char *semanage_fname(enum semanage_sandbox_defs file_enum); + +extern const char *semanage_path(enum semanage_store_defs store, + enum semanage_sandbox_defs file); + +extern const char *semanage_final_path(enum semanage_final_defs root, + enum semanage_final_path_defs suffix); + +int semanage_create_store(semanage_handle_t * sh, int create); + +int semanage_store_access_check(void); + +int semanage_remove_directory(const char *path); + +int semanage_mkdir(semanage_handle_t *sh, const char *path); + +int semanage_mkpath(semanage_handle_t *sh, const char *path); + +int semanage_make_sandbox(semanage_handle_t * sh); + +int semanage_make_final(semanage_handle_t * sh); + +int semanage_get_cil_paths(semanage_handle_t * sh, semanage_module_info_t *modinfos, + int len, char ***filenames); + +int semanage_get_active_modules(semanage_handle_t *sh, + semanage_module_info_t **modinfo, int *num_modules); + + +/* lock file routines */ +int semanage_get_trans_lock(semanage_handle_t * sh); +int semanage_get_active_lock(semanage_handle_t * sh); +void semanage_release_trans_lock(semanage_handle_t * sh); +void semanage_release_active_lock(semanage_handle_t * sh); +int semanage_direct_get_serial(semanage_handle_t * sh); + +int semanage_load_files(semanage_handle_t * sh, + cil_db_t *cildb, char **filenames, int num_modules); + +int semanage_read_policydb(semanage_handle_t * sh, + sepol_policydb_t * policydb); + +int semanage_write_policydb(semanage_handle_t * sh, + sepol_policydb_t * policydb); + +int semanage_install_sandbox(semanage_handle_t * sh); + +int semanage_verify_modules(semanage_handle_t * sh, + char **module_filenames, int num_modules); + +int semanage_verify_linked(semanage_handle_t * sh); +int semanage_verify_kernel(semanage_handle_t * sh); +int semanage_split_fc(semanage_handle_t * sh); + +/* sort file context routines */ +int semanage_fc_sort(semanage_handle_t * sh, + const char *buf, + size_t buf_len, + char **sorted_buf, size_t * sorted_buf_len); + +/* sort netfilter context routines */ +int semanage_nc_sort(semanage_handle_t * sh, + const char *buf, + size_t buf_len, + char **sorted_buf, size_t * sorted_buf_len); + +int semanage_copy_file(const char *src, const char *dst, mode_t mode); + +#endif
diff --git a/selinux/libsemanage/src/semanageswig.i b/selinux/libsemanage/src/semanageswig.i new file mode 100644 index 0000000..583b7d8 --- /dev/null +++ b/selinux/libsemanage/src/semanageswig.i
@@ -0,0 +1,51 @@ +/* Author: Spencer Shimko <sshimko@tresys.com> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * Copyright (C) 2006 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +%module semanage + +/* pull in the headers */ +%include "../include/semanage/debug.h" +%include "../include/semanage/handle.h" +%include "../include/semanage/modules.h" +%include "../include/semanage/context_record.h" +%include "../include/semanage/boolean_record.h" +%include "../include/semanage/booleans_policy.h" +%include "../include/semanage/booleans_local.h" +%include "../include/semanage/booleans_active.h" +%include "../include/semanage/iface_record.h" +%include "../include/semanage/interfaces_local.h" +%include "../include/semanage/interfaces_policy.h" +%include "../include/semanage/user_record.h" +%include "../include/semanage/users_local.h" +%include "../include/semanage/users_policy.h" +%include "../include/semanage/port_record.h" +%include "../include/semanage/ports_local.h" +%include "../include/semanage/ports_policy.h" +%include "../include/semanage/fcontext_record.h" +%include "../include/semanage/fcontexts_local.h" +%include "../include/semanage/fcontexts_policy.h" +%include "../include/semanage/seuser_record.h" +%include "../include/semanage/seusers_local.h" +%include "../include/semanage/seusers_policy.h" +%include "../include/semanage/node_record.h" +%include "../include/semanage/nodes_local.h" +%include "../include/semanage/nodes_policy.h" +%include "../include/semanage/semanage.h"
diff --git a/selinux/libsemanage/src/semanageswig_python.i b/selinux/libsemanage/src/semanageswig_python.i new file mode 100644 index 0000000..1346b2e --- /dev/null +++ b/selinux/libsemanage/src/semanageswig_python.i
@@ -0,0 +1,485 @@ +/* Author: Spencer Shimko <sshimko@tresys.com> + * + * Copyright (C) 2004-2005 Tresys Technology, LLC + * Copyright (C) 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** standard typemaps **/ + +%header %{ + #include <stdlib.h> + #include <semanage/semanage.h> + #include <sys/mman.h> + + #define STATUS_SUCCESS 0 + #define STATUS_ERR -1 +%} + +%include "stdint.i" +%ignore semanage_module_install_pp; +%ignore semanage_module_install_hll; + +%wrapper %{ + + + /* There are two ways to call this function: + * One is with a valid swig_type and destructor. + * Two is with a NULL swig_type and NULL destructor. + * + * In the first mode, the function converts + * an array of *cloned* objects [of the given pointer swig type] + * into a PyList, and destroys the array in the process + * (the objects pointers are preserved). + * + * In the second mode, the function converts + * an array of *constant* strings into a PyList, and destroys + * the array in the process + * (the strings are copied, originals not freed). */ + + static int semanage_array2plist( + semanage_handle_t* handle, + void** arr, + unsigned int asize, + swig_type_info* swig_type, + void (*destructor) (void*), + PyObject** result) { + + PyObject* plist = PyList_New(0); + unsigned int i; + + if (!plist) + goto err; + + for (i = 0; i < asize; i++) { + + PyObject* obj = NULL; + + /* NULL indicates string conversion, + * otherwise create an opaque pointer */ + if (!swig_type) + obj = SWIG_FromCharPtr(arr[i]); + else + obj = SWIG_NewPointerObj(arr[i], swig_type, 0); + + if (!obj) + goto err; + + if (PyList_Append(plist, obj) < 0) + goto err; + } + + free(arr); + + *result = plist; + return STATUS_SUCCESS; + + err: + for (i = 0; i < asize; i++) + if (destructor) + destructor(arr[i]); + free(arr); + return STATUS_ERR; + } +%} +/* a few helpful typemaps are available in this library */ +%include <typemaps.i> +/* wrap all int*'s so they can be used for results + if it becomes necessary to send in data this should be changed to INOUT */ +%apply int *OUTPUT { int * }; +%apply int *OUTPUT { size_t * }; +%apply int *OUTPUT { unsigned int * }; +%apply int *OUTPUT { uint16_t * }; + +%include <cstring.i> +/* This is needed to properly mmaped binary data in SWIG */ +%cstring_output_allocate_size(void **mapped_data, size_t *data_len, munmap(*$1, *$2)); + +%typemap(in, numinputs=0) char **(char *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) char** { + $result = SWIG_Python_AppendOutput($result, SWIG_FromCharPtr(*$1)); + free(*$1); +} + +%typemap(in, numinputs=0) char ***(char **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + const semanage_user_t* user, + const char*** roles_arr, + unsigned int* num_roles) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$3, *$4, + NULL, NULL, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +/** module typemaps**/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_module_info_t ** parameter */ +%typemap(in, numinputs=0) semanage_module_info_t **(semanage_module_info_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_module_info_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +/** module key typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_module_key_t ** parameter */ +%typemap(in, numinputs=0) semanage_module_key_t **(semanage_module_key_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_module_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +/** context typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_context_t ** parameter */ +%typemap(in, numinputs=0) semanage_context_t **(semanage_context_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_context_t** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +/** boolean typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_bool_t *** parameter */ +%typemap(in, numinputs=0) semanage_bool_t ***(semanage_bool_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_bool_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_bool, + (void (*) (void*)) &semanage_bool_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_bool_t **(semanage_bool_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_bool_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_bool_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_bool_key_t **(semanage_bool_key_t *temp=NULL) { + $1 = &temp; +} + +/** fcontext typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_fcontext_t *** parameter */ +%typemap(in, numinputs=0) semanage_fcontext_t ***(semanage_fcontext_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_fcontext_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_fcontext, + (void (*) (void*)) &semanage_fcontext_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_fcontext_t **(semanage_fcontext_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_fcontext_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_fcontext_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_fcontext_key_t **(semanage_fcontext_key_t *temp=NULL) { + $1 = &temp; +} + +/** interface typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_iface_t *** parameter */ +%typemap(in, numinputs=0) semanage_iface_t ***(semanage_iface_t **temp=NULL) { + $1 = &temp; +} + + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_iface_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_iface, + (void (*) (void*)) &semanage_iface_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_iface_t **(semanage_iface_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_iface_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_iface_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_iface_key_t **(semanage_iface_key_t *temp=NULL) { + $1 = &temp; +} + +/** seuser typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_seuser_t *** parameter */ +%typemap(in, numinputs=0) semanage_seuser_t ***(semanage_seuser_t **temp=NULL) { + $1 = &temp; +} + + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_seuser_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_seuser, + (void (*) (void*)) &semanage_seuser_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_seuser_t **(semanage_seuser_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_seuser_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_seuser_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_seuser_key_t **(semanage_seuser_key_t *temp=NULL) { + $1 = &temp; +} + +/** user typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_user_t *** parameter */ +%typemap(in, numinputs=0) semanage_user_t ***(semanage_user_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_user_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_user, + (void (*) (void*)) &semanage_user_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_user_t **(semanage_user_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_user_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_user_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_user_key_t **(semanage_user_key_t *temp=NULL) { + $1 = &temp; +} + +/** port typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_port_t *** parameter */ +%typemap(in, numinputs=0) semanage_port_t ***(semanage_port_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_port_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_port, + (void (*) (void*)) &semanage_port_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_port_t **(semanage_port_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_port_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_port_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_port_key_t **(semanage_port_key_t *temp=NULL) { + $1 = &temp; +} + +/** node typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_node_t *** parameter */ +%typemap(in, numinputs=0) semanage_node_t ***(semanage_node_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_node_t*** records, + unsigned int* count) { + + if ($result) { + int value; + SWIG_AsVal_int($result, &value); + if (value >= 0) { + PyObject* plist = NULL; + if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_node, + (void (*) (void*)) &semanage_node_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_node_t **(semanage_node_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_node_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + + +%typemap(argout) semanage_node_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_node_key_t **(semanage_node_key_t *temp=NULL) { + $1 = &temp; +} + +%include "semanageswig_python_exception.i" +%include "semanageswig.i"
diff --git a/selinux/libsemanage/src/semanageswig_ruby.i b/selinux/libsemanage/src/semanageswig_ruby.i new file mode 100644 index 0000000..e030e4a --- /dev/null +++ b/selinux/libsemanage/src/semanageswig_ruby.i
@@ -0,0 +1,225 @@ +/* Author Dave Quigley + * based on semanageswig_python.i by Spencer Shimko + */ + +%header %{ + #include <stdlib.h> + #include <semanage/semanage.h> + + #define STATUS_SUCCESS 0 + #define STATUS_ERR -1 +%} +/* a few helpful typemaps are available in this library */ +%include <typemaps.i> + +/* wrap all int*'s so they can be used for results + if it becomes necessary to send in data this should be changed to INOUT */ +%apply int *OUTPUT { int * }; +%apply int *OUTPUT { size_t * }; +%apply int *OUTPUT { unsigned int * }; + +%typemap(in, numinputs=0) char **(char *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) char** { + %append_output(SWIG_FromCharPtr(*$1)); + free(*$1); +} + +%typemap(in, numinputs=0) char ***(char **temp=NULL) { + $1 = &temp; +} + +/* the wrapper will setup this parameter for passing... the resulting ruby functions + will not take the semanage_module_info_t ** parameter */ +%typemap(in, numinputs=0) semanage_module_info_t **(semanage_module_info_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_module_info_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +/** context typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_context_t ** parameter */ +%typemap(in, numinputs=0) semanage_context_t **(semanage_context_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_context_t** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +/** boolean typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_bool_t *** parameter */ +%typemap(in, numinputs=0) semanage_bool_t ***(semanage_bool_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_bool_t **(semanage_bool_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_bool_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_bool_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_bool_key_t **(semanage_bool_key_t *temp=NULL) { + $1 = &temp; +} + +/** fcontext typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_fcontext_t *** parameter */ +%typemap(in, numinputs=0) semanage_fcontext_t ***(semanage_fcontext_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_fcontext_t **(semanage_fcontext_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_fcontext_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_fcontext_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_fcontext_key_t **(semanage_fcontext_key_t *temp=NULL) { + $1 = &temp; +} + +/** interface typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_iface_t *** parameter */ +%typemap(in, numinputs=0) semanage_iface_t ***(semanage_iface_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_iface_t **(semanage_iface_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_iface_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_iface_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_iface_key_t **(semanage_iface_key_t *temp=NULL) { + $1 = &temp; +} + +/** seuser typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_seuser_t *** parameter */ +%typemap(in, numinputs=0) semanage_seuser_t ***(semanage_seuser_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_seuser_t **(semanage_seuser_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_seuser_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_seuser_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_seuser_key_t **(semanage_seuser_key_t *temp=NULL) { + $1 = &temp; +} + +/** user typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_user_t *** parameter */ +%typemap(in, numinputs=0) semanage_user_t ***(semanage_user_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_user_t **(semanage_user_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_user_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_user_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_user_key_t **(semanage_user_key_t *temp=NULL) { + $1 = &temp; +} + +/** port typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_port_t *** parameter */ +%typemap(in, numinputs=0) semanage_port_t ***(semanage_port_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_port_t **(semanage_port_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_port_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_port_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_port_key_t **(semanage_port_key_t *temp=NULL) { + $1 = &temp; +} + +/** node typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_node_t *** parameter */ +%typemap(in, numinputs=0) semanage_node_t ***(semanage_node_t **temp=NULL) { + $1 = &temp; +} + +%typemap(in, numinputs=0) semanage_node_t **(semanage_node_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_node_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + + +%typemap(argout) semanage_node_key_t ** { + $result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_node_key_t **(semanage_node_key_t *temp=NULL) { + $1 = &temp; +} + +%include "semanageswig.i"
diff --git a/selinux/libsemanage/src/seuser_internal.h b/selinux/libsemanage/src/seuser_internal.h new file mode 100644 index 0000000..bf9cab0 --- /dev/null +++ b/selinux/libsemanage/src/seuser_internal.h
@@ -0,0 +1,43 @@ +#ifndef _SEMANAGE_SEUSER_INTERNAL_H_ +#define _SEMANAGE_SEUSER_INTERNAL_H_ + +#include <semanage/seuser_record.h> +#include <semanage/seusers_local.h> +#include <semanage/seusers_policy.h> +#include <sepol/policydb.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_seuser_clone) + hidden_proto(semanage_seuser_compare) + hidden_proto(semanage_seuser_compare2) + hidden_proto(semanage_seuser_create) + hidden_proto(semanage_seuser_free) + hidden_proto(semanage_seuser_get_mlsrange) + hidden_proto(semanage_seuser_get_name) + hidden_proto(semanage_seuser_get_sename) + hidden_proto(semanage_seuser_key_create) + hidden_proto(semanage_seuser_key_extract) + hidden_proto(semanage_seuser_key_free) + hidden_proto(semanage_seuser_set_mlsrange) + hidden_proto(semanage_seuser_set_name) + hidden_proto(semanage_seuser_set_sename) + hidden_proto(semanage_seuser_iterate) + hidden_proto(semanage_seuser_iterate_local) + +/* SEUSER RECORD: method table */ +extern record_table_t SEMANAGE_SEUSER_RTABLE; + +extern int seuser_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void seuser_file_dbase_release(dbase_config_t * dconfig); + +extern int hidden semanage_seuser_validate_local(semanage_handle_t * handle, + const sepol_policydb_t * + policydb); + +#endif
diff --git a/selinux/libsemanage/src/seuser_record.c b/selinux/libsemanage/src/seuser_record.c new file mode 100644 index 0000000..8823b1e --- /dev/null +++ b/selinux/libsemanage/src/seuser_record.c
@@ -0,0 +1,267 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_seuser_t (Unix User) + * Object: semanage_seuser_key_t (Unix User Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +struct semanage_seuser; +struct semanage_seuser_key; +typedef struct semanage_seuser record_t; +typedef struct semanage_seuser_key record_key_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include <string.h> +#include "seuser_internal.h" +#include "debug.h" +#include <semanage/handle.h> +#include "database.h" + +struct semanage_seuser { + /* This user's name */ + char *name; + + /* This user's corresponding + * seuser ("role set") */ + char *sename; + + /* This user's mls range (only required for mls) */ + char *mls_range; +}; + +struct semanage_seuser_key { + /* This user's name */ + const char *name; +}; + +int semanage_seuser_key_create(semanage_handle_t * handle, + const char *name, + semanage_seuser_key_t ** key_ptr) +{ + + semanage_seuser_key_t *tmp_key = (semanage_seuser_key_t *) + malloc(sizeof(semanage_seuser_key_t)); + + if (!tmp_key) { + ERR(handle, "out of memory, could not create seuser key"); + return STATUS_ERR; + } + tmp_key->name = name; + + *key_ptr = tmp_key; + return STATUS_SUCCESS; +} + +hidden_def(semanage_seuser_key_create) + +int semanage_seuser_key_extract(semanage_handle_t * handle, + const semanage_seuser_t * seuser, + semanage_seuser_key_t ** key_ptr) +{ + + if (semanage_seuser_key_create(handle, seuser->name, key_ptr) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not extract seuser key from record"); + return STATUS_ERR; +} + +hidden_def(semanage_seuser_key_extract) + +void semanage_seuser_key_free(semanage_seuser_key_t * key) +{ + + free(key); +} + +hidden_def(semanage_seuser_key_free) + +int semanage_seuser_compare(const semanage_seuser_t * seuser, + const semanage_seuser_key_t * key) +{ + + return strcmp(seuser->name, key->name); +} + +hidden_def(semanage_seuser_compare) + +int semanage_seuser_compare2(const semanage_seuser_t * seuser, + const semanage_seuser_t * seuser2) +{ + + return strcmp(seuser->name, seuser2->name); +} + +hidden_def(semanage_seuser_compare2) + +static int semanage_seuser_compare2_qsort(const semanage_seuser_t ** seuser, + const semanage_seuser_t ** seuser2) +{ + + return strcmp((*seuser)->name, (*seuser2)->name); +} + +/* Name */ +const char *semanage_seuser_get_name(const semanage_seuser_t * seuser) +{ + + return seuser->name; +} + +hidden_def(semanage_seuser_get_name) + +int semanage_seuser_set_name(semanage_handle_t * handle, + semanage_seuser_t * seuser, const char *name) +{ + + char *tmp_name = strdup(name); + if (!tmp_name) { + ERR(handle, "out of memory, could not set seuser (Unix) name"); + return STATUS_ERR; + } + free(seuser->name); + seuser->name = tmp_name; + return STATUS_SUCCESS; +} + +hidden_def(semanage_seuser_set_name) + +/* Selinux Name */ +const char *semanage_seuser_get_sename(const semanage_seuser_t * seuser) +{ + + return seuser->sename; +} + +hidden_def(semanage_seuser_get_sename) + +int semanage_seuser_set_sename(semanage_handle_t * handle, + semanage_seuser_t * seuser, const char *sename) +{ + + char *tmp_sename = strdup(sename); + if (!tmp_sename) { + ERR(handle, + "out of memory, could not set seuser (SELinux) name"); + return STATUS_ERR; + } + free(seuser->sename); + seuser->sename = tmp_sename; + return STATUS_SUCCESS; +} + +hidden_def(semanage_seuser_set_sename) + +/* MLS Range */ +const char *semanage_seuser_get_mlsrange(const semanage_seuser_t * seuser) +{ + + return seuser->mls_range; +} + +hidden_def(semanage_seuser_get_mlsrange) + +int semanage_seuser_set_mlsrange(semanage_handle_t * handle, + semanage_seuser_t * seuser, + const char *mls_range) +{ + + char *tmp_mls_range = strdup(mls_range); + if (!tmp_mls_range) { + ERR(handle, "out of memory, could not set seuser MLS range"); + return STATUS_ERR; + } + free(seuser->mls_range); + seuser->mls_range = tmp_mls_range; + return STATUS_SUCCESS; +} + +hidden_def(semanage_seuser_set_mlsrange) + +/* Create */ +int semanage_seuser_create(semanage_handle_t * handle, + semanage_seuser_t ** seuser_ptr) +{ + + semanage_seuser_t *seuser = + (semanage_seuser_t *) malloc(sizeof(semanage_seuser_t)); + + if (!seuser) { + ERR(handle, "out of memory, could not create seuser"); + return STATUS_ERR; + } + + seuser->name = NULL; + seuser->sename = NULL; + seuser->mls_range = NULL; + + *seuser_ptr = seuser; + return STATUS_SUCCESS; +} + +hidden_def(semanage_seuser_create) + +/* Deep copy clone */ +int semanage_seuser_clone(semanage_handle_t * handle, + const semanage_seuser_t * seuser, + semanage_seuser_t ** seuser_ptr) +{ + + semanage_seuser_t *new_seuser = NULL; + + if (semanage_seuser_create(handle, &new_seuser) < 0) + goto err; + + if (semanage_seuser_set_name(handle, new_seuser, seuser->name) < 0) + goto err; + + if (semanage_seuser_set_sename(handle, new_seuser, seuser->sename) < 0) + goto err; + + if (seuser->mls_range && + (semanage_seuser_set_mlsrange(handle, new_seuser, seuser->mls_range) + < 0)) + goto err; + + *seuser_ptr = new_seuser; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not clone seuser"); + semanage_seuser_free(new_seuser); + return STATUS_ERR; +} + +hidden_def(semanage_seuser_clone) + +/* Destroy */ +void semanage_seuser_free(semanage_seuser_t * seuser) +{ + + if (!seuser) + return; + + free(seuser->name); + free(seuser->sename); + free(seuser->mls_range); + free(seuser); +} + +hidden_def(semanage_seuser_free) + +/* Record base functions */ +record_table_t SEMANAGE_SEUSER_RTABLE = { + .create = semanage_seuser_create, + .key_extract = semanage_seuser_key_extract, + .key_free = semanage_seuser_key_free, + .clone = semanage_seuser_clone, + .compare = semanage_seuser_compare, + .compare2 = semanage_seuser_compare2, + .compare2_qsort = semanage_seuser_compare2_qsort, + .free = semanage_seuser_free, +};
diff --git a/selinux/libsemanage/src/seusers_file.c b/selinux/libsemanage/src/seusers_file.c new file mode 100644 index 0000000..910bedf --- /dev/null +++ b/selinux/libsemanage/src/seusers_file.c
@@ -0,0 +1,138 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_seuser; +struct semanage_seuser_key; +typedef struct semanage_seuser record_t; +typedef struct semanage_seuser_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> + +#include "seuser_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" +#include "handle.h" + +static int seuser_print(semanage_handle_t * handle, + semanage_seuser_t * seuser, FILE * str) +{ + + const char *name = semanage_seuser_get_name(seuser); + const char *sename = semanage_seuser_get_sename(seuser); + const char *mls = semanage_seuser_get_mlsrange(seuser); + + if (fprintf(str, "%s:%s", name, sename) < 0) + goto err; + + if (mls != NULL && fprintf(str, ":%s", mls) < 0) + goto err; + + fprintf(str, "\n"); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not print seuser %s to stream", name); + return STATUS_ERR; +} + +static int seuser_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_seuser_t * seuser) +{ + + char *str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Extract name */ + if (parse_fetch_string(handle, info, &str, ':') < 0) + goto err; + if (semanage_seuser_set_name(handle, seuser, str) < 0) + goto err; + free(str); + str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_assert_ch(handle, info, ':') < 0) + goto err; + if (parse_skip_space(handle, info) < 0) + goto err; + + /* Extract sename */ + if (parse_fetch_string(handle, info, &str, ':') < 0) + goto err; + if (semanage_seuser_set_sename(handle, seuser, str) < 0) + goto err; + free(str); + str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_optional_ch(info, ':') == STATUS_NODATA) + goto out; + if (parse_skip_space(handle, info) < 0) + goto err; + + /* NOTE: does not allow spaces/multiline */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + + if (semanage_seuser_set_mlsrange(handle, seuser, str) < 0) + goto err; + free(str); + str = NULL; + + if (parse_assert_space(handle, info) < 0) + goto err; + + out: + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse seuser record"); + free(str); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* SEUSER RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_SEUSER_FILE_RTABLE = { + .parse = seuser_parse, + .print = seuser_print, +}; + +int seuser_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_SEUSER_RTABLE, + &SEMANAGE_SEUSER_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void seuser_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/seusers_local.c b/selinux/libsemanage/src/seusers_local.c new file mode 100644 index 0000000..42c3a8b --- /dev/null +++ b/selinux/libsemanage/src/seusers_local.c
@@ -0,0 +1,326 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_seuser; +struct semanage_seuser_key; +typedef struct semanage_seuser_key record_key_t; +typedef struct semanage_seuser record_t; +#define DBASE_RECORD_DEFINED + +#include <sepol/policydb.h> +#include <sepol/context.h> +#include <libaudit.h> +#include <errno.h> +#include "user_internal.h" +#include "seuser_internal.h" +#include "handle.h" +#include "database.h" +#include "debug.h" +#include "string.h" +#include <stdlib.h> + +static char *semanage_user_roles(semanage_handle_t * handle, const char *sename) { + char *roles = NULL; + unsigned int num_roles; + size_t i; + size_t size = 0; + const char **roles_arr; + semanage_user_key_t *key = NULL; + semanage_user_t * user; + if (semanage_user_key_create(handle, sename, &key) >= 0) { + if (semanage_user_query(handle, key, &user) >= 0) { + if (semanage_user_get_roles(handle, + user, + &roles_arr, + &num_roles) >= 0) { + for (i = 0; i<num_roles; i++) { + size += (strlen(roles_arr[i]) + 1); + } + roles = malloc(size); + if (roles) { + strcpy(roles,roles_arr[0]); + for (i = 1; i<num_roles; i++) { + strcat(roles,","); + strcat(roles,roles_arr[i]); + } + } + } + semanage_user_free(user); + } + semanage_user_key_free(key); + } + return roles; +} + +static int semanage_seuser_audit(semanage_handle_t * handle, + const semanage_seuser_t * seuser, + const semanage_seuser_t * previous, + int audit_type, + int success) { + const char *name = NULL; + const char *sename = NULL; + char *roles = NULL; + const char *mls = NULL; + const char *psename = NULL; + const char *pmls = NULL; + char *proles = NULL; + char msg[1024]; + const char *sep = "-"; + int rc = -1; + strcpy(msg, "login"); + if (seuser) { + name = semanage_seuser_get_name(seuser); + sename = semanage_seuser_get_sename(seuser); + mls = semanage_seuser_get_mlsrange(seuser); + roles = semanage_user_roles(handle, sename); + } + if (previous) { + psename = semanage_seuser_get_sename(previous); + pmls = semanage_seuser_get_mlsrange(previous); + proles = semanage_user_roles(handle, psename); + } + if (audit_type != AUDIT_ROLE_REMOVE) { + if (sename && (!psename || strcmp(psename, sename) != 0)) { + strcat(msg,sep); + strcat(msg,"sename"); + sep = ","; + } + if (roles && (!proles || strcmp(proles, roles) != 0)) { + strcat(msg,sep); + strcat(msg,"role"); + sep = ","; + } + if (mls && (!pmls || strcmp(pmls, mls) != 0)) { + strcat(msg,sep); + strcat(msg,"range"); + } + } + + int fd = audit_open(); + if (fd < 0) + { + /* If kernel doesn't support audit, bail out */ + if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { + rc = 0; + goto err; + } + rc = fd; + goto err; + } + audit_log_semanage_message(fd, audit_type, NULL, msg, name, 0, sename, roles, mls, psename, proles, pmls, NULL, NULL,NULL, success); + rc = 0; +err: + audit_close(fd); + free(roles); + free(proles); + return rc; +} + +int semanage_seuser_modify_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + const semanage_seuser_t * data) +{ + int rc; + void *callback = (void *) handle->msg_callback; + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + const char *sename = semanage_seuser_get_sename(data); + const char *mls_range = semanage_seuser_get_mlsrange(data); + semanage_seuser_t *previous = NULL; + semanage_seuser_t *new = NULL; + + if (!sename) { + errno=EINVAL; + return -1; + } + rc = semanage_seuser_clone(handle, data, &new); + if (rc < 0) { + goto err; + } + + if (!mls_range && semanage_mls_enabled(handle)) { + semanage_user_key_t *ukey = NULL; + semanage_user_t *u = NULL; + rc = semanage_user_key_create(handle, sename, &ukey); + if (rc < 0) + goto err; + + rc = semanage_user_query(handle, ukey, &u); + semanage_user_key_free(ukey); + if (rc >= 0 ) { + mls_range = semanage_user_get_mlsrange(u); + rc = semanage_seuser_set_mlsrange(handle, new, mls_range); + semanage_user_free(u); + } + if (rc < 0) + goto err; + } + + handle->msg_callback = NULL; + (void) semanage_seuser_query(handle, key, &previous); + handle->msg_callback = callback; + rc = dbase_modify(handle, dconfig, key, new); + if (semanage_seuser_audit(handle, new, previous, AUDIT_ROLE_ASSIGN, rc == 0) < 0) + rc = -1; +err: + if (previous) + semanage_seuser_free(previous); + semanage_seuser_free(new); + return rc; +} + +int semanage_seuser_del_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key) +{ + int rc; + semanage_seuser_t *seuser = NULL; + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + rc = dbase_del(handle, dconfig, key); + semanage_seuser_query(handle, key, &seuser); + if (semanage_seuser_audit(handle, NULL, seuser, AUDIT_ROLE_REMOVE, rc == 0) < 0) + rc = -1; + if (seuser) + semanage_seuser_free(seuser); + return rc; +} + +int semanage_seuser_query_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + semanage_seuser_t ** response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_seuser_exists_local(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + int *response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_seuser_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_seuser_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_seuser_t * + record, void *varg), + void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +hidden_def(semanage_seuser_iterate_local) + +int semanage_seuser_list_local(semanage_handle_t * handle, + semanage_seuser_t *** records, + unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +} + +struct validate_handler_arg { + semanage_handle_t *handle; + const sepol_policydb_t *policydb; +}; + +static int validate_handler(const semanage_seuser_t * seuser, void *varg) +{ + + semanage_user_t *user = NULL; + semanage_user_key_t *key = NULL; + int exists, mls_ok; + + /* Unpack varg */ + struct validate_handler_arg *arg = (struct validate_handler_arg *)varg; + semanage_handle_t *handle = arg->handle; + const sepol_policydb_t *policydb = arg->policydb; + + /* Unpack seuser */ + const char *name = semanage_seuser_get_name(seuser); + const char *sename = semanage_seuser_get_sename(seuser); + const char *mls_range = semanage_seuser_get_mlsrange(seuser); + const char *user_mls_range; + + /* Make sure the (SElinux) user exists */ + if (semanage_user_key_create(handle, sename, &key) < 0) + goto err; + if (semanage_user_exists(handle, key, &exists) < 0) + goto err; + if (!exists) { + ERR(handle, "selinux user %s does not exist", sename); + goto invalid; + } + + /* Verify that the mls range is valid, and that it's contained + * within the (SELinux) user mls range. This range is optional */ + if (mls_range && sepol_policydb_mls_enabled(policydb)) { + + if (semanage_user_query(handle, key, &user) < 0) + goto err; + user_mls_range = semanage_user_get_mlsrange(user); + + if (sepol_mls_check(handle->sepolh, policydb, mls_range) < 0) + goto invalid; + if (sepol_mls_contains(handle->sepolh, policydb, + user_mls_range, mls_range, &mls_ok) < 0) + goto err; + + if (!mls_ok) { + ERR(handle, "MLS range %s for Unix user %s " + "exceeds allowed range %s for SELinux user %s", + mls_range, name, user_mls_range, sename); + goto invalid; + } + + } else if (mls_range) { + ERR(handle, "MLS is disabled, but MLS range %s " + "was found for Unix user %s", mls_range, name); + goto invalid; + } + + semanage_user_key_free(key); + semanage_user_free(user); + return 0; + + err: + ERR(handle, "could not check if seuser mapping for %s is valid", name); + semanage_user_key_free(key); + semanage_user_free(user); + return -1; + + invalid: + if (mls_range) + ERR(handle, "seuser mapping [%s -> (%s, %s)] is invalid", + name, sename, mls_range); + else + ERR(handle, "seuser mapping [%s -> %s] is invalid", + name, sename); + semanage_user_key_free(key); + semanage_user_free(user); + return -1; +} + +/* This function may not be called outside a transaction, or + * it will (1) deadlock, because iterate is not reentrant outside + * a transaction, and (2) be racy, because it makes multiple dbase calls */ + +int hidden semanage_seuser_validate_local(semanage_handle_t * handle, + const sepol_policydb_t * policydb) +{ + + struct validate_handler_arg arg; + arg.handle = handle; + arg.policydb = policydb; + return semanage_seuser_iterate_local(handle, validate_handler, &arg); +}
diff --git a/selinux/libsemanage/src/seusers_policy.c b/selinux/libsemanage/src/seusers_policy.c new file mode 100644 index 0000000..89fb4d8 --- /dev/null +++ b/selinux/libsemanage/src/seusers_policy.c
@@ -0,0 +1,58 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_seuser; +struct semanage_seuser_key; +typedef struct semanage_seuser_key record_key_t; +typedef struct semanage_seuser record_t; +#define DBASE_RECORD_DEFINED + +#include <sepol/policydb.h> +#include <sepol/context.h> +#include "user_internal.h" +#include "seuser_internal.h" +#include "handle.h" +#include "database.h" +#include "debug.h" + +int semanage_seuser_query(semanage_handle_t * handle, + const semanage_seuser_key_t * key, + semanage_seuser_t ** response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_seuser_exists(semanage_handle_t * handle, + const semanage_seuser_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_seuser_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_seuser_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_seuser_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +hidden_def(semanage_seuser_iterate) + +int semanage_seuser_list(semanage_handle_t * handle, + semanage_seuser_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_seuser_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/user_base_record.c b/selinux/libsemanage/src/user_base_record.c new file mode 100644 index 0000000..7dfa8c6 --- /dev/null +++ b/selinux/libsemanage/src/user_base_record.c
@@ -0,0 +1,184 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_user_base_t (SELinux User/Class Policy Object) + * Object: semanage_user_key_t (SELinux User/Class Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/user_record.h> + +typedef sepol_user_key_t semanage_user_key_t; +#define _SEMANAGE_USER_KEY_DEFINED_ + +typedef sepol_user_t semanage_user_base_t; +#define _SEMANAGE_USER_BASE_DEFINED_ + +typedef semanage_user_base_t record_t; +typedef semanage_user_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include "user_internal.h" +#include "handle.h" +#include "database.h" +#include "debug.h" + +/* Key */ +hidden int semanage_user_base_key_extract(semanage_handle_t * handle, + const semanage_user_base_t * user, + semanage_user_key_t ** key) +{ + + return sepol_user_key_extract(handle->sepolh, user, key); +} + +static int semanage_user_base_compare(const semanage_user_base_t * user, + const semanage_user_key_t * key) +{ + + return sepol_user_compare(user, key); +} + +static int semanage_user_base_compare2(const semanage_user_base_t * user, + const semanage_user_base_t * user2) +{ + + return sepol_user_compare2(user, user2); +} + +static int semanage_user_base_compare2_qsort(const semanage_user_base_t ** user, + const semanage_user_base_t ** + user2) +{ + + return sepol_user_compare2(*user, *user2); +} + +/* Name */ +hidden const char *semanage_user_base_get_name(const semanage_user_base_t * + user) +{ + + return sepol_user_get_name(user); +} + +hidden int semanage_user_base_set_name(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *name) +{ + + return sepol_user_set_name(handle->sepolh, user, name); +} + +/* MLS */ +hidden const char *semanage_user_base_get_mlslevel(const semanage_user_base_t * + user) +{ + + return sepol_user_get_mlslevel(user); +} + +hidden int semanage_user_base_set_mlslevel(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *mls_level) +{ + + return sepol_user_set_mlslevel(handle->sepolh, user, mls_level); +} + +hidden const char *semanage_user_base_get_mlsrange(const semanage_user_base_t * + user) +{ + + return sepol_user_get_mlsrange(user); +} + +hidden int semanage_user_base_set_mlsrange(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *mls_range) +{ + + return sepol_user_set_mlsrange(handle->sepolh, user, mls_range); +} + +/* Role management */ +hidden int semanage_user_base_get_num_roles(const semanage_user_base_t * user) +{ + + return sepol_user_get_num_roles(user); +} + +hidden int semanage_user_base_add_role(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *role) +{ + + return sepol_user_add_role(handle->sepolh, user, role); +} + +hidden void semanage_user_base_del_role(semanage_user_base_t * user, + const char *role) +{ + + sepol_user_del_role(user, role); +} + +hidden int semanage_user_base_has_role(const semanage_user_base_t * user, + const char *role) +{ + + return sepol_user_has_role(user, role); +} + +hidden int semanage_user_base_get_roles(semanage_handle_t * handle, + const semanage_user_base_t * user, + const char ***roles_arr, + unsigned int *num_roles) +{ + + return sepol_user_get_roles(handle->sepolh, user, roles_arr, num_roles); +} + +hidden int semanage_user_base_set_roles(semanage_handle_t * handle, + semanage_user_base_t * user, + const char **roles_arr, + unsigned int num_roles) +{ + + return sepol_user_set_roles(handle->sepolh, user, roles_arr, num_roles); +} + +/* Create/Clone/Destroy */ +hidden int semanage_user_base_create(semanage_handle_t * handle, + semanage_user_base_t ** user_ptr) +{ + + return sepol_user_create(handle->sepolh, user_ptr); +} + +hidden int semanage_user_base_clone(semanage_handle_t * handle, + const semanage_user_base_t * user, + semanage_user_base_t ** user_ptr) +{ + + return sepol_user_clone(handle->sepolh, user, user_ptr); +} + +hidden void semanage_user_base_free(semanage_user_base_t * user) +{ + + sepol_user_free(user); +} + +/* Record base functions */ +record_table_t SEMANAGE_USER_BASE_RTABLE = { + .create = semanage_user_base_create, + .key_extract = semanage_user_base_key_extract, + .key_free = semanage_user_key_free, + .clone = semanage_user_base_clone, + .compare = semanage_user_base_compare, + .compare2 = semanage_user_base_compare2, + .compare2_qsort = semanage_user_base_compare2_qsort, + .free = semanage_user_base_free, +};
diff --git a/selinux/libsemanage/src/user_extra_record.c b/selinux/libsemanage/src/user_extra_record.c new file mode 100644 index 0000000..efb9c5b --- /dev/null +++ b/selinux/libsemanage/src/user_extra_record.c
@@ -0,0 +1,197 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_user_extra_t (SELinux User/Class Extra Data) + * Object: semanage_user_extra_key_t (SELinux User/Class Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/user_record.h> + +typedef sepol_user_key_t semanage_user_key_t; +#define _SEMANAGE_USER_KEY_DEFINED_ + +struct semanage_user_extra; +typedef struct semanage_user_extra record_t; +typedef semanage_user_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include <semanage/handle.h> +#include <stdlib.h> +#include <string.h> +#include "user_internal.h" +#include "debug.h" +#include "database.h" + +struct semanage_user_extra { + /* This user's name */ + char *name; + + /* Labeling prefix */ + char *prefix; +}; + +static int semanage_user_extra_key_extract(semanage_handle_t * handle, + const semanage_user_extra_t * + user_extra, + semanage_user_key_t ** key_ptr) +{ + + if (semanage_user_key_create(handle, user_extra->name, key_ptr) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not extract key from user extra record"); + return STATUS_ERR; +} + +static int semanage_user_extra_compare(const semanage_user_extra_t * user_extra, + const semanage_user_key_t * key) +{ + + const char *name; + semanage_user_key_unpack(key, &name); + + return strcmp(user_extra->name, name); +} + +static int semanage_user_extra_compare2(const semanage_user_extra_t * + user_extra, + const semanage_user_extra_t * + user_extra2) +{ + + return strcmp(user_extra->name, user_extra2->name); +} + +static int semanage_user_extra_compare2_qsort(const semanage_user_extra_t ** + user_extra, + const semanage_user_extra_t ** + user_extra2) +{ + + return strcmp((*user_extra)->name, (*user_extra2)->name); +} + +/* Name */ +hidden const char *semanage_user_extra_get_name(const semanage_user_extra_t * + user_extra) +{ + + return user_extra->name; +} + +hidden int semanage_user_extra_set_name(semanage_handle_t * handle, + semanage_user_extra_t * user_extra, + const char *name) +{ + + char *tmp_name = strdup(name); + if (!tmp_name) { + ERR(handle, "out of memory, could not set name %s " + "for user extra data", name); + return STATUS_ERR; + } + free(user_extra->name); + user_extra->name = tmp_name; + return STATUS_SUCCESS; +} + +/* Labeling prefix */ +hidden const char *semanage_user_extra_get_prefix(const semanage_user_extra_t * + user_extra) +{ + + return user_extra->prefix; +} + +hidden int semanage_user_extra_set_prefix(semanage_handle_t * handle, + semanage_user_extra_t * user_extra, + const char *prefix) +{ + + char *tmp_prefix = strdup(prefix); + if (!tmp_prefix) { + ERR(handle, "out of memory, could not set prefix %s " + "for user %s", prefix, user_extra->name); + return STATUS_ERR; + } + free(user_extra->prefix); + user_extra->prefix = tmp_prefix; + return STATUS_SUCCESS; +} + +/* Create */ +hidden int semanage_user_extra_create(semanage_handle_t * handle, + semanage_user_extra_t ** user_extra_ptr) +{ + + semanage_user_extra_t *user_extra = + (semanage_user_extra_t *) malloc(sizeof(semanage_user_extra_t)); + + if (!user_extra) { + ERR(handle, "out of memory, could not " + "create user extra data record"); + return STATUS_ERR; + } + + user_extra->name = NULL; + user_extra->prefix = NULL; + + *user_extra_ptr = user_extra; + return STATUS_SUCCESS; +} + +/* Destroy */ +hidden void semanage_user_extra_free(semanage_user_extra_t * user_extra) +{ + + if (!user_extra) + return; + + free(user_extra->name); + free(user_extra->prefix); + free(user_extra); +} + +/* Deep copy clone */ +hidden int semanage_user_extra_clone(semanage_handle_t * handle, + const semanage_user_extra_t * user_extra, + semanage_user_extra_t ** user_extra_ptr) +{ + + semanage_user_extra_t *new_user_extra = NULL; + + if (semanage_user_extra_create(handle, &new_user_extra) < 0) + goto err; + + if (semanage_user_extra_set_name + (handle, new_user_extra, user_extra->name) < 0) + goto err; + + if (semanage_user_extra_set_prefix + (handle, new_user_extra, user_extra->prefix) < 0) + goto err; + + *user_extra_ptr = new_user_extra; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not clone extra data for user %s", user_extra->name); + semanage_user_extra_free(new_user_extra); + return STATUS_ERR; +} + +/* Record base functions */ +record_table_t SEMANAGE_USER_EXTRA_RTABLE = { + .create = semanage_user_extra_create, + .key_extract = semanage_user_extra_key_extract, + .key_free = semanage_user_key_free, + .clone = semanage_user_extra_clone, + .compare = semanage_user_extra_compare, + .compare2 = semanage_user_extra_compare2, + .compare2_qsort = semanage_user_extra_compare2_qsort, + .free = semanage_user_extra_free, +};
diff --git a/selinux/libsemanage/src/user_internal.h b/selinux/libsemanage/src/user_internal.h new file mode 100644 index 0000000..ce1ac31 --- /dev/null +++ b/selinux/libsemanage/src/user_internal.h
@@ -0,0 +1,177 @@ +#ifndef _SEMANAGE_USER_INTERNAL_H_ +#define _SEMANAGE_USER_INTERNAL_H_ + +#include <sepol/user_record.h> +#include <semanage/user_record.h> +#include <semanage/users_local.h> +#include <semanage/users_policy.h> +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_user_add_role) + hidden_proto(semanage_user_clone) + hidden_proto(semanage_user_compare) + hidden_proto(semanage_user_compare2) + hidden_proto(semanage_user_create) + hidden_proto(semanage_user_free) + hidden_proto(semanage_user_get_mlslevel) + hidden_proto(semanage_user_get_mlsrange) + hidden_proto(semanage_user_get_name) + hidden_proto(semanage_user_get_roles) + hidden_proto(semanage_user_key_create) + hidden_proto(semanage_user_key_extract) + hidden_proto(semanage_user_key_free) + hidden_proto(semanage_user_set_mlslevel) + hidden_proto(semanage_user_set_mlsrange) + hidden_proto(semanage_user_set_name) + hidden_proto(semanage_user_exists) + hidden_proto(semanage_user_query) + +/* USER record: metod table */ +extern record_table_t SEMANAGE_USER_RTABLE; + +/* USER BASE record: method table */ +extern record_table_t SEMANAGE_USER_BASE_RTABLE; + +/* USER EXTRA record: method table */ +extern record_table_t SEMANAGE_USER_EXTRA_RTABLE; + +/* ============ Init/Release functions ========== */ + +/* USER BASE record, FILE backend */ +extern int user_base_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void user_base_file_dbase_release(dbase_config_t * dconfig); + +/* USER EXTRA record, FILE backend */ +extern int user_extra_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig); + +extern void user_extra_file_dbase_release(dbase_config_t * dconfig); + +/* USER BASE record, POLICYDB backend */ +extern int user_base_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig); + +extern void user_base_policydb_dbase_release(dbase_config_t * dconfig); + +/* USER record, JOIN backend */ +extern int user_join_dbase_init(semanage_handle_t * handle, + dbase_config_t * join1, + dbase_config_t * join2, + dbase_config_t * dconfig); + +extern void user_join_dbase_release(dbase_config_t * dconfig); + +/*======= Internal API: Base (Policy) User record ====== */ + +#ifndef _SEMANAGE_USER_BASE_DEFINED_ +struct semanage_user_base; +typedef struct semanage_user_base semanage_user_base_t; +#define _SEMANAGE_USER_BASE_DEFINED_ +#endif + +hidden int semanage_user_base_create(semanage_handle_t * handle, + semanage_user_base_t ** user_ptr); + +hidden int semanage_user_base_clone(semanage_handle_t * handle, + const semanage_user_base_t * user, + semanage_user_base_t ** user_ptr); + +hidden int semanage_user_base_key_extract(semanage_handle_t * handle, + const semanage_user_base_t * user, + semanage_user_key_t ** key); + +hidden const char *semanage_user_base_get_name(const semanage_user_base_t * + user); + +hidden int semanage_user_base_set_name(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *name); + +hidden const char *semanage_user_base_get_mlslevel(const semanage_user_base_t * + user); + +hidden int semanage_user_base_set_mlslevel(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *mls_level); + +hidden const char *semanage_user_base_get_mlsrange(const semanage_user_base_t * + user); + +hidden int semanage_user_base_set_mlsrange(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *mls_range); + +hidden int semanage_user_base_get_num_roles(const semanage_user_base_t * user); + +hidden int semanage_user_base_add_role(semanage_handle_t * handle, + semanage_user_base_t * user, + const char *role); + +hidden void semanage_user_base_del_role(semanage_user_base_t * user, + const char *role); + +hidden int semanage_user_base_has_role(const semanage_user_base_t * user, + const char *role); + +hidden int semanage_user_base_get_roles(semanage_handle_t * handle, + const semanage_user_base_t * user, + const char ***roles_arr, + unsigned int *num_roles); + +hidden int semanage_user_base_set_roles(semanage_handle_t * handle, + semanage_user_base_t * user, + const char **roles_arr, + unsigned int num_roles); + +hidden void semanage_user_base_free(semanage_user_base_t * user); + +/*=========== Internal API: Extra User record ==========*/ +struct semanage_user_extra; +typedef struct semanage_user_extra semanage_user_extra_t; + +hidden int semanage_user_extra_create(semanage_handle_t * handle, + semanage_user_extra_t ** user_extra_ptr); + +hidden int semanage_user_extra_clone(semanage_handle_t * handle, + const semanage_user_extra_t * user_extra, + semanage_user_extra_t ** user_extra_ptr); + +hidden const char *semanage_user_extra_get_name(const semanage_user_extra_t * + user_extra); + +hidden int semanage_user_extra_set_name(semanage_handle_t * handle, + semanage_user_extra_t * user_extra, + const char *name); + +hidden const char *semanage_user_extra_get_prefix(const semanage_user_extra_t * + user_extra); + +hidden int semanage_user_extra_set_prefix(semanage_handle_t * handle, + semanage_user_extra_t * user_extra, + const char *prefix); + +hidden void semanage_user_extra_free(semanage_user_extra_t * user_extra); + +/*======== Internal API: Join record ========== */ +hidden void semanage_user_key_unpack(const semanage_user_key_t * key, + const char **name); + +hidden int semanage_user_join(semanage_handle_t * handle, + const semanage_user_base_t * record1, + const semanage_user_extra_t * record2, + semanage_user_t ** result); + +hidden int semanage_user_split(semanage_handle_t * handle, + const semanage_user_t * record, + semanage_user_base_t ** split1, + semanage_user_extra_t ** split2); + +#endif
diff --git a/selinux/libsemanage/src/user_record.c b/selinux/libsemanage/src/user_record.c new file mode 100644 index 0000000..4523925 --- /dev/null +++ b/selinux/libsemanage/src/user_record.c
@@ -0,0 +1,410 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: semanage_user_t (SELinux User/Class) + * Object: semanage_user_key_t (SELinux User/Class Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include <sepol/user_record.h> + +typedef sepol_user_key_t semanage_user_key_t; +#define _SEMANAGE_USER_KEY_DEFINED_ + +struct semanage_user; +typedef struct semanage_user record_t; +typedef semanage_user_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include <stdlib.h> +#include <string.h> +#include "user_internal.h" +#include "handle.h" +#include "database.h" +#include "debug.h" + +struct semanage_user { + char *name; + semanage_user_base_t *base; + semanage_user_extra_t *extra; +}; + +/* Key */ +int semanage_user_key_create(semanage_handle_t * handle, + const char *name, semanage_user_key_t ** key) +{ + + return sepol_user_key_create(handle->sepolh, name, key); +} + +hidden_def(semanage_user_key_create) + +int semanage_user_key_extract(semanage_handle_t * handle, + const semanage_user_t * user, + semanage_user_key_t ** key) +{ + + return semanage_user_base_key_extract(handle, user->base, key); +} + +hidden_def(semanage_user_key_extract) + +void semanage_user_key_free(semanage_user_key_t * key) +{ + + sepol_user_key_free(key); +} + +hidden_def(semanage_user_key_free) + +hidden void semanage_user_key_unpack(const semanage_user_key_t * key, + const char **name) +{ + + sepol_user_key_unpack(key, name); +} + +int semanage_user_compare(const semanage_user_t * user, + const semanage_user_key_t * key) +{ + + const char *name; + sepol_user_key_unpack(key, &name); + return strcmp(user->name, name); +} + +hidden_def(semanage_user_compare) + +int semanage_user_compare2(const semanage_user_t * user, + const semanage_user_t * user2) +{ + + return strcmp(user->name, user2->name); +} + +hidden_def(semanage_user_compare2) + +static int semanage_user_compare2_qsort(const semanage_user_t ** user, + const semanage_user_t ** user2) +{ + + return strcmp((*user)->name, (*user2)->name); +} + +/* Name */ +const char *semanage_user_get_name(const semanage_user_t * user) +{ + return user->name; +} + +hidden_def(semanage_user_get_name) + +int semanage_user_set_name(semanage_handle_t * handle, + semanage_user_t * user, const char *name) +{ + + char *tmp_name = strdup(name); + if (!tmp_name) + goto omem; + + if (semanage_user_base_set_name(handle, user->base, name) < 0) + goto err; + + if (semanage_user_extra_set_name(handle, user->extra, name) < 0) + goto err; + + free(user->name); + user->name = tmp_name; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not set user name to %s", name); + free(tmp_name); + return STATUS_ERR; +} + +hidden_def(semanage_user_set_name) + +/* Labeling prefix */ +const char *semanage_user_get_prefix(const semanage_user_t * user) +{ + + return semanage_user_extra_get_prefix(user->extra); +} + +int semanage_user_set_prefix(semanage_handle_t * handle, + semanage_user_t * user, const char *name) +{ + + return semanage_user_extra_set_prefix(handle, user->extra, name); +} + +/* MLS */ +const char *semanage_user_get_mlslevel(const semanage_user_t * user) +{ + + return semanage_user_base_get_mlslevel(user->base); +} + +hidden_def(semanage_user_get_mlslevel) + +int semanage_user_set_mlslevel(semanage_handle_t * handle, + semanage_user_t * user, const char *mls_level) +{ + + return semanage_user_base_set_mlslevel(handle, user->base, mls_level); +} + +hidden_def(semanage_user_set_mlslevel) + +const char *semanage_user_get_mlsrange(const semanage_user_t * user) +{ + + return semanage_user_base_get_mlsrange(user->base); +} + +hidden_def(semanage_user_get_mlsrange) + +int semanage_user_set_mlsrange(semanage_handle_t * handle, + semanage_user_t * user, const char *mls_range) +{ + + return semanage_user_base_set_mlsrange(handle, user->base, mls_range); +} + +hidden_def(semanage_user_set_mlsrange) + +/* Role management */ +int semanage_user_get_num_roles(const semanage_user_t * user) +{ + + return semanage_user_base_get_num_roles(user->base); +} + +int semanage_user_add_role(semanage_handle_t * handle, + semanage_user_t * user, const char *role) +{ + + return semanage_user_base_add_role(handle, user->base, role); +} + +hidden_def(semanage_user_add_role) + +void semanage_user_del_role(semanage_user_t * user, const char *role) +{ + + semanage_user_base_del_role(user->base, role); +} + +int semanage_user_has_role(const semanage_user_t * user, const char *role) +{ + + return semanage_user_base_has_role(user->base, role); +} + +int semanage_user_get_roles(semanage_handle_t * handle, + const semanage_user_t * user, + const char ***roles_arr, unsigned int *num_roles) +{ + + return semanage_user_base_get_roles(handle, user->base, roles_arr, + num_roles); +} + +hidden_def(semanage_user_get_roles) + +int semanage_user_set_roles(semanage_handle_t * handle, + semanage_user_t * user, + const char **roles_arr, unsigned int num_roles) +{ + + return semanage_user_base_set_roles(handle, user->base, roles_arr, + num_roles); +} + +/* Create/Clone/Destroy */ +int semanage_user_create(semanage_handle_t * handle, + semanage_user_t ** user_ptr) +{ + + semanage_user_t *tmp_user = calloc(1, sizeof(semanage_user_t)); + if (!tmp_user) + goto omem; + + if (semanage_user_base_create(handle, &tmp_user->base) < 0) + goto err; + if (semanage_user_extra_create(handle, &tmp_user->extra) < 0) + goto err; + + /* Initialize the prefix for migration purposes */ + if (semanage_user_extra_set_prefix(handle, tmp_user->extra, "user") < 0) + goto err; + + *user_ptr = tmp_user; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not create user record"); + semanage_user_free(tmp_user); + return STATUS_ERR; +} + +hidden_def(semanage_user_create) + +int semanage_user_clone(semanage_handle_t * handle, + const semanage_user_t * user, + semanage_user_t ** user_ptr) +{ + + semanage_user_t *tmp_user = calloc(1, sizeof(semanage_user_t)); + if (!tmp_user) + goto omem; + + /* Clone base and extra records */ + if (semanage_user_base_clone(handle, user->base, &tmp_user->base) < 0) + goto err; + if (semanage_user_extra_clone(handle, user->extra, &tmp_user->extra) < + 0) + goto err; + + /* Set the shared name */ + if (semanage_user_set_name(handle, tmp_user, user->name) < 0) + goto err; + + *user_ptr = tmp_user; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not clone user record"); + semanage_user_free(tmp_user); + return STATUS_ERR; +} + +hidden_def(semanage_user_clone) + +void semanage_user_free(semanage_user_t * user) +{ + + if (!user) + return; + + semanage_user_base_free(user->base); + semanage_user_extra_free(user->extra); + free(user->name); + free(user); +} + +hidden_def(semanage_user_free) + +/* Join properties */ +hidden int semanage_user_join(semanage_handle_t * handle, + const semanage_user_base_t * record1, + const semanage_user_extra_t * record2, + semanage_user_t ** result) +{ + + const char *name; + semanage_user_t *tmp_user = calloc(1, sizeof(semanage_user_t)); + if (!tmp_user) + goto omem; + + /* Set the shared name from one of the records + * (at least one is available) */ + if (record1 == NULL) + name = semanage_user_extra_get_name(record2); + else + name = semanage_user_base_get_name(record1); + + /* Join base record if it exists, create a blank one otherwise */ + if (record1) { + if (semanage_user_base_clone(handle, record1, &tmp_user->base) < + 0) + goto err; + } else { + if (semanage_user_base_create(handle, &tmp_user->base) < 0) + goto err; + if (semanage_user_base_set_name(handle, tmp_user->base, name) < + 0) + goto err; + } + + /* Join extra record if it exists, create a blank one otherwise */ + if (record2) { + if (semanage_user_extra_clone(handle, record2, &tmp_user->extra) + < 0) + goto err; + } else { + if (semanage_user_extra_create(handle, &tmp_user->extra) < 0) + goto err; + if (semanage_user_extra_set_name(handle, tmp_user->extra, name) + < 0) + goto err; + if (semanage_user_extra_set_prefix + (handle, tmp_user->extra, "user") < 0) + goto err; + } + + if (semanage_user_set_name(handle, tmp_user, name) < 0) + goto err; + + *result = tmp_user; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not join data records for user %s", + semanage_user_base_get_name(record1)); + semanage_user_free(tmp_user); + return STATUS_ERR; +} + +hidden int semanage_user_split(semanage_handle_t * handle, + const semanage_user_t * record, + semanage_user_base_t ** split1, + semanage_user_extra_t ** split2) +{ + + semanage_user_base_t *tmp_base_user = NULL; + semanage_user_extra_t *tmp_extra_user = NULL; + + if (semanage_user_base_clone(handle, record->base, &tmp_base_user) < 0) + goto err; + + if (semanage_user_extra_clone(handle, record->extra, &tmp_extra_user) < + 0) + goto err; + + *split1 = tmp_base_user; + *split2 = tmp_extra_user; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not split data records for user %s", + semanage_user_get_name(record)); + semanage_user_base_free(tmp_base_user); + semanage_user_extra_free(tmp_extra_user); + return STATUS_ERR; +} + +/* Record base functions */ +record_table_t SEMANAGE_USER_RTABLE = { + .create = semanage_user_create, + .key_extract = semanage_user_key_extract, + .key_free = semanage_user_key_free, + .clone = semanage_user_clone, + .compare = semanage_user_compare, + .compare2 = semanage_user_compare2, + .compare2_qsort = semanage_user_compare2_qsort, + .free = semanage_user_free, +};
diff --git a/selinux/libsemanage/src/users_base_file.c b/selinux/libsemanage/src/users_base_file.c new file mode 100644 index 0000000..0f0a8fd --- /dev/null +++ b/selinux/libsemanage/src/users_base_file.c
@@ -0,0 +1,226 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user_base; +struct semanage_user_key; +typedef struct semanage_user_base record_t; +typedef struct semanage_user_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <semanage/handle.h> +#include "user_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int user_base_print(semanage_handle_t * handle, + semanage_user_base_t * user, FILE * str) +{ + + const char **roles = NULL; + unsigned int i, nroles; + + const char *name = semanage_user_base_get_name(user); + const char *mls_level = semanage_user_base_get_mlslevel(user); + const char *mls_range = semanage_user_base_get_mlsrange(user); + + if (fprintf(str, "user %s roles { ", name) < 0) + goto err; + + if (semanage_user_base_get_roles(handle, user, &roles, &nroles) < 0) + goto err; + + for (i = 0; i < nroles; i++) { + if (fprintf(str, "%s ", roles[i]) < 0) + goto err; + } + + if (fprintf(str, "} ") < 0) + goto err; + + /* MLS */ + if (mls_level != NULL && mls_range != NULL) + if (fprintf(str, "level %s range %s", mls_level, mls_range) < 0) + goto err; + + if (fprintf(str, ";\n") < 0) + goto err; + + free(roles); + return STATUS_SUCCESS; + + err: + free(roles); + ERR(handle, "could not print user %s to stream", name); + return STATUS_ERR; +} + +static int user_base_parse(semanage_handle_t * handle, + parse_info_t * info, semanage_user_base_t * user) +{ + + int islist = 0; + char *str = NULL; + char *start; + char *name_str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* Parse user header */ + if (parse_assert_str(handle, info, "user") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Parse user name */ + if (parse_fetch_string(handle, info, &name_str, ' ') < 0) + goto err; + + if (semanage_user_base_set_name(handle, user, name_str) < 0) { + free(name_str); + goto err; + } + free(name_str); + + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_assert_str(handle, info, "roles") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + islist = (parse_optional_ch(info, '{') != STATUS_NODATA); + + /* For each role, loop */ + do { + char delim; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_assert_noeof(handle, info) < 0) + goto err; + + start = info->ptr; + while (*(info->ptr) && + *(info->ptr) != ';' && + *(info->ptr) != '}' && !isspace(*(info->ptr))) + info->ptr++; + + delim = *(info->ptr); + *(info->ptr)++ = '\0'; + + if (semanage_user_base_add_role(handle, user, start) < 0) + goto err; + + if (delim && !isspace(delim)) { + if (islist && delim == '}') + break; + else if (!islist && delim == ';') + goto skip_semicolon; + else + goto err; + } + + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_optional_ch(info, ';') != STATUS_NODATA) + goto skip_semicolon; + if (parse_optional_ch(info, '}') != STATUS_NODATA) + islist = 0; + + } while (islist); + + /* Handle mls */ + /* Parse level header */ + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_optional_str(info, "level") == STATUS_NODATA) + goto semicolon; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* NOTE: does not allow spaces/multiline */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_user_base_set_mlslevel(handle, user, str) < 0) + goto err; + free(str); + str = NULL; + + /* Parse range header */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_assert_str(handle, info, "range") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* NOTE: does not allow spaces/multiline */ + if (parse_fetch_string(handle, info, &str, ';') < 0) + goto err; + if (semanage_user_base_set_mlsrange(handle, user, str) < 0) + goto err; + + free(str); + str = NULL; + + /* Check for semicolon */ + semicolon: + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_assert_ch(handle, info, ';') < 0) + goto err; + + skip_semicolon: + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse user record"); + free(str); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* USER BASE record: FILE extension: method table */ +record_file_table_t SEMANAGE_USER_BASE_FILE_RTABLE = { + .parse = user_base_parse, + .print = user_base_print, +}; + +int user_base_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_USER_BASE_RTABLE, + &SEMANAGE_USER_BASE_FILE_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void user_base_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/users_base_policydb.c b/selinux/libsemanage/src/users_base_policydb.c new file mode 100644 index 0000000..b42279c --- /dev/null +++ b/selinux/libsemanage/src/users_base_policydb.c
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user_base; +struct semanage_user_key; +typedef struct semanage_user_base record_t; +typedef struct semanage_user_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <sepol/users.h> +#include <semanage/handle.h> +#include "user_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* USER BASE record: POLICYDB extension: method table */ +record_policydb_table_t SEMANAGE_USER_BASE_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t) sepol_user_modify, + .set = NULL, + .query = (record_policydb_table_query_t) sepol_user_query, + .count = (record_policydb_table_count_t) sepol_user_count, + .exists = (record_policydb_table_exists_t) sepol_user_exists, + .iterate = (record_policydb_table_iterate_t) sepol_user_iterate, +}; + +int user_base_policydb_dbase_init(semanage_handle_t * handle, + dbase_config_t * dconfig) +{ + + if (dbase_policydb_init(handle, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + &SEMANAGE_USER_BASE_RTABLE, + &SEMANAGE_USER_BASE_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + return STATUS_SUCCESS; +} + +void user_base_policydb_dbase_release(dbase_config_t * dconfig) +{ + + dbase_policydb_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/users_extra_file.c b/selinux/libsemanage/src/users_extra_file.c new file mode 100644 index 0000000..8f2bebd --- /dev/null +++ b/selinux/libsemanage/src/users_extra_file.c
@@ -0,0 +1,130 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user_extra; +struct semanage_user_key; +typedef struct semanage_user_extra record_t; +typedef struct semanage_user_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> + +#include "user_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" +#include "handle.h" + +static int user_extra_print(semanage_handle_t * handle, + semanage_user_extra_t * user_extra, FILE * str) +{ + + const char *name = semanage_user_extra_get_name(user_extra); + const char *prefix = semanage_user_extra_get_prefix(user_extra); + + if (fprintf(str, "user %s prefix %s;\n", name, prefix) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not print user extra data " + "for %s to stream", name); + return STATUS_ERR; +} + +static int user_extra_parse(semanage_handle_t * handle, + parse_info_t * info, + semanage_user_extra_t * user_extra) +{ + + char *str = NULL; + + if (parse_skip_space(handle, info) < 0) + goto err; + if (!info->ptr) + goto last; + + /* User string */ + if (parse_assert_str(handle, info, "user") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Extract name */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_user_extra_set_name(handle, user_extra, str) < 0) + goto err; + free(str); + str = NULL; + + /* Prefix string */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_assert_str(handle, info, "prefix") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Extract prefix */ + if (parse_fetch_string(handle, info, &str, ';') < 0) + goto err; + if (semanage_user_extra_set_prefix(handle, user_extra, str) < 0) + goto err; + free(str); + str = NULL; + + /* Semicolon */ + if (parse_skip_space(handle, info) < 0) + goto err; + if (parse_assert_ch(handle, info, ';') < 0) + goto err; + + return STATUS_SUCCESS; + + last: + parse_dispose_line(info); + return STATUS_NODATA; + + err: + ERR(handle, "could not parse user extra data"); + free(str); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* USER EXTRA RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_USER_EXTRA_FILE_RTABLE = { + .parse = user_extra_parse, + .print = user_extra_print, +}; + +int user_extra_file_dbase_init(semanage_handle_t * handle, + const char *path_ro, + const char *path_rw, + dbase_config_t * dconfig) +{ + + if (dbase_file_init(handle, + path_ro, + path_rw, + &SEMANAGE_USER_EXTRA_RTABLE, + &SEMANAGE_USER_EXTRA_FILE_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void user_extra_file_dbase_release(dbase_config_t * dconfig) +{ + + dbase_file_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/users_join.c b/selinux/libsemanage/src/users_join.c new file mode 100644 index 0000000..b598209 --- /dev/null +++ b/selinux/libsemanage/src/users_join.c
@@ -0,0 +1,49 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user; +struct semanage_user_key; +typedef struct semanage_user record_t; +typedef struct semanage_user_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct semanage_user_base; +struct semanage_user_extra; +typedef struct semanage_user_base record1_t; +typedef struct semanage_user_extra record2_t; +#define DBASE_RECORD_JOIN_DEFINED + +struct dbase_join; +typedef struct dbase_join dbase_t; +#define DBASE_DEFINED + +#include <semanage/handle.h> +#include "user_internal.h" +#include "database_join.h" +#include "debug.h" + +/* USER record: JOIN extension: method table */ +record_join_table_t SEMANAGE_USER_JOIN_RTABLE = { + .join = semanage_user_join, + .split = semanage_user_split, +}; + +int user_join_dbase_init(semanage_handle_t * handle, + dbase_config_t * join1, + dbase_config_t * join2, dbase_config_t * dconfig) +{ + + if (dbase_join_init(handle, + &SEMANAGE_USER_RTABLE, + &SEMANAGE_USER_JOIN_RTABLE, + join1, join2, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_JOIN_DTABLE; + return STATUS_SUCCESS; +} + +void user_join_dbase_release(dbase_config_t * dconfig) +{ + + dbase_join_release(dconfig->dbase); +}
diff --git a/selinux/libsemanage/src/users_local.c b/selinux/libsemanage/src/users_local.c new file mode 100644 index 0000000..7aa43d4 --- /dev/null +++ b/selinux/libsemanage/src/users_local.c
@@ -0,0 +1,109 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user; +struct semanage_user_key; +typedef struct semanage_user_key record_key_t; +typedef struct semanage_user record_t; +#define DBASE_RECORD_DEFINED + +#include <string.h> +#include <stdlib.h> +#include "user_internal.h" +#include "seuser_internal.h" +#include "handle.h" +#include "database.h" +#include "errno.h" +#include "debug.h" + +int semanage_user_modify_local(semanage_handle_t * handle, + const semanage_user_key_t * key, + const semanage_user_t * data) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_modify(handle, dconfig, key, data); +} + +static int lookup_seuser(semanage_handle_t * handle, const semanage_user_key_t *k) { + semanage_user_t *user; + semanage_seuser_t **records; + const char *name; + const char *sename; + unsigned int count; + size_t i; + int rc = 0; + if (semanage_user_query(handle, k, &user) < 0) + return 0; + name = semanage_user_get_name(user); + semanage_seuser_list_local(handle, + &records, + &count); + for(i=0; i<count; i++) { + sename = semanage_seuser_get_sename(records[i]); + if (strcmp(name, sename) == 0) { + errno = EINVAL; + ERR(handle, "%s is being used by %s login record", + sename, semanage_seuser_get_name(records[i])); + rc = -1; + } + } + for(i=0; i<count; i++) + semanage_seuser_free(records[i]); + free(records); + semanage_user_free(user); + if (rc) + errno = EINVAL; + return rc; +} + +int semanage_user_del_local(semanage_handle_t * handle, + const semanage_user_key_t * key) +{ + if (lookup_seuser(handle, key)) + return -1; + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_del(handle, dconfig, key); +} + +int semanage_user_query_local(semanage_handle_t * handle, + const semanage_user_key_t * key, + semanage_user_t ** response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_query(handle, dconfig, key, response); +} + +int semanage_user_exists_local(semanage_handle_t * handle, + const semanage_user_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_user_count_local(semanage_handle_t * handle, + unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_user_iterate_local(semanage_handle_t * handle, + int (*handler) (const semanage_user_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_user_list_local(semanage_handle_t * handle, + semanage_user_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_user_dbase_local(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/users_policy.c b/selinux/libsemanage/src/users_policy.c new file mode 100644 index 0000000..74f59dc --- /dev/null +++ b/selinux/libsemanage/src/users_policy.c
@@ -0,0 +1,56 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +struct semanage_user; +struct semanage_user_key; +typedef struct semanage_user_key record_key_t; +typedef struct semanage_user record_t; +#define DBASE_RECORD_DEFINED + +#include "user_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_user_query(semanage_handle_t * handle, + const semanage_user_key_t * key, + semanage_user_t ** response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_policy(handle); + return dbase_query(handle, dconfig, key, response); +} + +hidden_def(semanage_user_query) + +int semanage_user_exists(semanage_handle_t * handle, + const semanage_user_key_t * key, int *response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_policy(handle); + return dbase_exists(handle, dconfig, key, response); +} + +hidden_def(semanage_user_exists) + +int semanage_user_count(semanage_handle_t * handle, unsigned int *response) +{ + + dbase_config_t *dconfig = semanage_user_dbase_policy(handle); + return dbase_count(handle, dconfig, response); +} + +int semanage_user_iterate(semanage_handle_t * handle, + int (*handler) (const semanage_user_t * record, + void *varg), void *handler_arg) +{ + + dbase_config_t *dconfig = semanage_user_dbase_policy(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_user_list(semanage_handle_t * handle, + semanage_user_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_user_dbase_policy(handle); + return dbase_list(handle, dconfig, records, count); +}
diff --git a/selinux/libsemanage/src/utilities.c b/selinux/libsemanage/src/utilities.c new file mode 100644 index 0000000..f48ffa4 --- /dev/null +++ b/selinux/libsemanage/src/utilities.c
@@ -0,0 +1,308 @@ +/* Author: Mark Goldman <mgoldman@tresys.com> + * Paul Rosenfeld <prosenfeld@tresys.com> + * + * Copyright (C) 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 "utilities.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <sys/types.h> +#include <assert.h> +#include <ustr.h> + +#define TRUE 1 +#define FALSE 0 + +char *semanage_findval(const char *file, const char *var, const char *delim) +{ + FILE *fd; + char *buff = NULL; + char *retval = NULL; + size_t buff_len = 0; + + assert(file); + assert(var); + + if ((fd = fopen(file, "r")) == NULL) + return NULL; + + while (getline(&buff, &buff_len, fd) > 0) { + if (semanage_is_prefix(buff, var)) { + retval = semanage_split(buff, delim); + if (retval) + semanage_rtrim(retval, '\n'); + break; + } + } + free(buff); + fclose(fd); + + return retval; +} + +int semanage_is_prefix(const char *str, const char *prefix) +{ + if (!str) { + return FALSE; + } + if (!prefix) { + return TRUE; + } + + return strncmp(str, prefix, strlen(prefix)) == 0; +} + +char *semanage_split_on_space(const char *str) +{ + /* as per the man page, these are the isspace() chars */ + const char *seps = "\f\n\r\t\v "; + size_t slen = strlen(seps); + size_t off = 0, rside_len = 0; + char *retval = NULL; + Ustr *ustr = USTR_NULL, *temp = USTR_NULL; + + if (!str) + goto done; + if (!(ustr = ustr_dup_cstr(str))) + goto done; + temp = + ustr_split_spn_chrs(ustr, &off, seps, slen, USTR_NULL, + USTR_FLAG_SPLIT_DEF); + if (!temp) + goto done; + /* throw away the left hand side */ + ustr_sc_free(&temp); + + rside_len = ustr_len(ustr) - off; + temp = ustr_dup_subustr(ustr, off + 1, rside_len); + if (!temp) + goto done; + retval = strdup(ustr_cstr(temp)); + ustr_sc_free(&temp); + + done: + ustr_sc_free(&ustr); + return retval; +} + +char *semanage_split(const char *str, const char *delim) +{ + Ustr *ustr = USTR_NULL, *temp = USTR_NULL; + size_t off = 0, rside_len = 0; + char *retval = NULL; + + if (!str) + goto done; + if (!delim || !(*delim)) + return semanage_split_on_space(str); + ustr = ustr_dup_cstr(str); + temp = + ustr_split_cstr(ustr, &off, delim, USTR_NULL, USTR_FLAG_SPLIT_DEF); + if (!temp) + goto done; + /* throw away the left hand side */ + ustr_sc_free(&temp); + + rside_len = ustr_len(ustr) - off; + + temp = ustr_dup_subustr(ustr, off + 1, rside_len); + if (!temp) + goto done; + retval = strdup(ustr_cstr(temp)); + ustr_sc_free(&temp); + + done: + ustr_sc_free(&ustr); + return retval; +} + +int semanage_list_push(semanage_list_t ** list, const char *data) +{ + semanage_list_t *temp = NULL; + + if (!data) + return EINVAL; + + if (semanage_list_find(*list, data) != NULL) + return 0; + + if (!(temp = malloc(sizeof(semanage_list_t)))) + return ENOMEM; + + if (!(temp->data = strdup(data))) { + free(temp); + return ENOMEM; + } + temp->next = *list; + *list = temp; + + return 0; +} + +char *semanage_list_pop(semanage_list_t ** list) +{ + semanage_list_t *node = NULL; + char *data = NULL; + + if (!list || !(*list)) + return NULL; + + node = (*list); + data = node->data; + + (*list) = node->next; + free(node); + + return data; +} + +void semanage_list_destroy(semanage_list_t ** list) +{ + semanage_list_t *temp; + + while ((temp = (*list))) { + free(temp->data); + (*list) = temp->next; + free(temp); + } +} + +semanage_list_t *semanage_list_find(semanage_list_t * l, const char *data) +{ + if (!data) + return NULL; + while (l && strcmp(l->data, data)) + l = l->next; + + return l; +} + +int semanage_list_sort(semanage_list_t ** l) +{ + semanage_list_t **array = NULL; + semanage_list_t *temp = NULL; + size_t count = 0; + size_t i = 0; + + if (!l) + return 0; + + for (temp = *l; temp; temp = temp->next) + ++count; + + array = malloc(sizeof(semanage_list_t *) * count); + if (!array) + return ENOMEM; /* couldn't allocate memory for sort */ + for (temp = *l; temp; temp = temp->next) { + array[i++] = temp; + } + + qsort(array, count, sizeof(semanage_list_t *), + (int (*)(const void *, const void *))&semanage_cmp_plist_t); + for (i = 0; i < (count - 1); ++i) { + array[i]->next = array[i + 1]; + } + array[i]->next = NULL; + (*l) = array[0]; + free(array); + + return 0; +} + +int semanage_cmp_plist_t(const semanage_list_t ** x, const semanage_list_t ** y) +{ + return strcmp((*x)->data, (*y)->data); +} + +int semanage_str_count(char *data, char what) +{ + int count = 0; + + if (!data) + return 0; + while (*data) { + if (*data == what) + ++count; + ++data; + } + + return count; +} + +void semanage_rtrim(char *str, char trim_to) +{ + int len = 0; + + if (!str) + return; + len = strlen(str); + + while (len > 0) { + if (str[--len] == trim_to) { + str[len] = '\0'; + return; + } + } +} + +/* list_addafter_controlmem does *NOT* duplicate the data argument + * use at your own risk, I am building a list out of malloc'd memory and + * it is only going to get stored into this list, thus when I destroy it + * later I won't free a ptr twice. + * + * returns the newly created node or NULL on error + */ +semanage_list_t *list_addafter_controlmem(semanage_list_t * item, char *data) +{ + semanage_list_t *temp = malloc(sizeof(semanage_list_t)); + + if (!temp) + return NULL; + temp->data = data; + temp->next = item->next; + item->next = temp; + + return temp; +} + +semanage_list_t *semanage_slurp_file_filter(FILE * file, + int (*pred) (const char *)) +{ + semanage_list_t head; + semanage_list_t *current = &head; + char *line = NULL; + size_t buff_len = 0; + + head.next = NULL; /* initialize head, we aren't going to use the data */ + while (getline(&line, &buff_len, file) >= 0) { + if (pred(line)) { + semanage_rtrim(line, '\n'); + current = list_addafter_controlmem(current, line); + if (!current) + break; + line = NULL; + buff_len = 0; + } + } + free(line); + + return head.next; +}
diff --git a/selinux/libsemanage/src/utilities.h b/selinux/libsemanage/src/utilities.h new file mode 100644 index 0000000..5fa15ef --- /dev/null +++ b/selinux/libsemanage/src/utilities.h
@@ -0,0 +1,137 @@ +/* Author: Mark Goldman <mgoldman@tresys.com> + * + * Copyright (C) 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 + */ + +/* This file contains helper functions that are loosely based off of what is + * available from the python script genhomedircon. Also this file contains + * c implementations of a couple of python functions so that genhomedircon will + * look/act like the python script. + */ +#ifndef _SEMANAGE_UTILITIES_H_ +#define _SEMANAGE_UTILITIES_H_ + +#include <stdio.h> + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define WARN_UNUSED \ + __attribute__ ((__warn_unused_result__)) +#else +# define WARN_UNUSED /* nothing */ +#endif + +typedef struct list { + char *data; + struct list *next; +} semanage_list_t; + +/** + * @param file the path to the file to look for a variable in + * @param var the variable that you want the value of + * @param delim the value that separates the part you care about from the part + * that you don't. + * @return for the first instance of var in the file, returns everything after + * delim. + * returns "" if not found IE if(*(semanage_findval(f,v,d)) == '\0'){ + * printf("%s not found in file", v); + * } + * + * NULL for error (out of memory, etc) + */ +char *semanage_findval(const char *file, const char *var, const char *delim) WARN_UNUSED; + +/** + * @param str string to test + * @param val prefix + * @return 1 if val is the prefix of str + * 0 if val is not the prefix of str + * + * note: if str == NULL, returns false + * if val == NULL, returns true --nothing can always be the prefix of + * something + * if (*val) == "" returns true same as above. + */ +int semanage_is_prefix(const char *str, const char *val) WARN_UNUSED; + +/** + * @param str the string to semanage_split + * @return malloc'd string after the first run of charachters that aren't whitespace + */ +char *semanage_split_on_space(const char *str) WARN_UNUSED; + +/** + * @param str the string to semanage_split + * @param delim the string delimiter. NOT a set of charachters that can be + * a delimiter. + * if *delim == '\0' behaves as semanage_splitOnSpace() + * @return a ptr to the first charachter past the delimiter. + * if delim doesn't appear in the string, returns a ptr to the + * trailing null in the string + */ +char *semanage_split(const char *str, const char *delim) WARN_UNUSED; + +/* linked list string functions + * Functions allocate memory. Must be free'd with + * either semanage_list_pop until list == NULL or semanage_list_destroy() + */ +int semanage_list_push(semanage_list_t ** list, const char *data) WARN_UNUSED; +char *semanage_list_pop(semanage_list_t ** list); +void semanage_list_destroy(semanage_list_t ** list); +semanage_list_t *semanage_list_find(semanage_list_t * l, + const char *data) WARN_UNUSED; +int semanage_list_sort(semanage_list_t ** l) WARN_UNUSED; +/* function to compare 2 semanage_list_t nodes, + * returns strcmp(x->data, y->data) + * used internally by semanage_list_sort() + */ +int semanage_cmp_plist_t(const semanage_list_t ** x, + const semanage_list_t ** y); +/** + * @param data a target string + * @param what a charachter + * @returns the number of times the char appears in the string + */ +int semanage_str_count(char *data, char what); +/** + * @param - a string + * @param the charachter to trim to + * @return - mangles the string, converting the first + * occurrance of the charachter to a '\0' from + * the end of the string. + */ +void semanage_rtrim(char *str, char trim_to); + +/** + * @param data some string + * @return modifies the string such that the first whitespace char becomes + * '\0', ending the string. + */ +void semanage_keep_until_space(char *data); + +/** + * @param file - an open FILE to read from + * @param pred - a function taking a string that + * returns 1 if the string should be + * kept and 0 otherwise + * @return a list of lines from the file (empty lines become + * empty strings) in the file order where pred(line) + * returns > 0 + */ +semanage_list_t *semanage_slurp_file_filter(FILE * file, + int (*pred) (const char *)) + WARN_UNUSED; +#endif
diff --git a/selinux/libsemanage/tests/Makefile b/selinux/libsemanage/tests/Makefile new file mode 100644 index 0000000..fec96ff --- /dev/null +++ b/selinux/libsemanage/tests/Makefile
@@ -0,0 +1,32 @@ +# Add your test source files here: +SOURCES = $(wildcard *.c) + +# Point this variable to the libsemanage source directory you want to test: +TESTSRC=../src + +# Add the required external object files here: +LIBS = ../src/libsemanage.a ../../libselinux/src/libselinux.a ../../libsepol/src/libsepol.a + +########################################################################### + +EXECUTABLE = libsemanage-tests +CC = gcc +CFLAGS += -g -O0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter +INCLUDE = -I$(TESTSRC) -I$(TESTSRC)/../include +LDFLAGS += -lcunit -lustr -lbz2 -laudit +OBJECTS = $(SOURCES:.c=.o) + +all: $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(OBJECTS) $(LIBS) $(LDFLAGS) -o $@ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $*.c -o $*.o + +clean distclean: + rm -rf $(OBJECTS) $(EXECUTABLE) + +test: all + ./$(EXECUTABLE) +
diff --git a/selinux/libsemanage/tests/README b/selinux/libsemanage/tests/README new file mode 100644 index 0000000..424970c --- /dev/null +++ b/selinux/libsemanage/tests/README
@@ -0,0 +1,64 @@ +Notes on tests +============================ +The semanage_access_check test in the semanage_store suite simulates a +read-only filesystem by using DAC permissions. Consequently, these tests +will fail if run as root, as root can override DAC permissions. + + +How to add and use unit tests +============================= + +We are using the CUnit unit testing framework. This framework--and the +official documentation of the framework--may be found here: + +http://cunit.sourceforge.net/ + +If you have not yet installed CUnit, first do that. (There is an RPM, +or you can compile from source.) Once installed, follow these steps to +add unit tests for your code: + +1. Create a .h and .c file corresponding to the .c file you want to test. + For example, test_semanage_store.c provides tests of the functions in + semanage_store.c. Your new .h/.c files represent a suite of related + tests. + +2. Write or add new tests to a suite. Tests are simply functions that + take the form: + + void test_my_function(void) + + These tests are where you will make calls to the CUnit assertions. + + If you are making a new test suite, also add the suite init/cleanup + functions. These take the form: + + int <suite_name>_test_init(void) + int <suite_name>_cleanup(void) + + These functions will be called before and after the test functions + in your suite, respectively. They return 0 on success, 1 on failure. + +3. Update libsemanage-tests.c to add your new suite and/or your new tests + using the DECLARE_SUITE macro in do_tests(). + +4. Update the Makefile: + + Make sure that the TESTSRC variable is set to the location + of the libsemanage source code you want to test. + +5. Compile the libsemanage source code you will be testing, to ensure + the object files are available and up to date. + +6. Run your tests. Rejoice or despair, as appropriate. + + +A note on the the utilities.c: Add functions that can be commonly used +here. For example, it is handy to have a dummy message callback +function to silence error messages produced by libsemanage and keep +your output pretty. To do this, include utilities.h and specify the +callback like so: + + semanage_handle_t *sh; + sh = semanage_handle_create(); + sh->msg_callback = test_msg_handler; + +Feel free to add other such functions here as well.
diff --git a/selinux/libsemanage/tests/libsemanage-tests.c b/selinux/libsemanage/tests/libsemanage-tests.c new file mode 100644 index 0000000..735d36f --- /dev/null +++ b/selinux/libsemanage/tests/libsemanage-tests.c
@@ -0,0 +1,108 @@ +/* Authors: Christopher Ashworth <cashworth@tresys.com> + * Caleb Case <ccase@tresys.com> + * Chad Sellers <csellers@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "test_semanage_store.h" +#include "test_utilities.h" + +#include <CUnit/Basic.h> +#include <CUnit/Console.h> +#include <CUnit/TestDB.h> + +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> + +#define DECLARE_SUITE(name) \ + suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \ + if (NULL == suite) { \ + CU_cleanup_registry(); \ + return CU_get_error(); } \ + if (name##_add_tests(suite)) { \ + CU_cleanup_registry(); \ + return CU_get_error(); } + +static void usage(char *progname) +{ + printf("usage: %s [options]\n", progname); + printf("options:\n"); + printf("\t-v, --verbose\t\t\tverbose output\n"); + printf("\t-i, --interactive\t\tinteractive console\n"); +} + +static int do_tests(int interactive, int verbose) +{ + CU_pSuite suite = NULL; + + /* Initialize the CUnit test registry. */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + DECLARE_SUITE(semanage_store); + DECLARE_SUITE(semanage_utilities); + + if (verbose) + CU_basic_set_mode(CU_BRM_VERBOSE); + else + CU_basic_set_mode(CU_BRM_NORMAL); + + if (interactive) + CU_console_run_tests(); + else + CU_basic_run_tests(); + CU_cleanup_registry(); + return CU_get_error(); + +} + +/* The main function for setting up and running the libsemanage unit tests. + * Returns a CUE_SUCCESS on success, or a CUnit error code on failure. + */ +int main(int argc, char **argv) +{ + int i, verbose = 1, interactive = 0; + + struct option opts[] = { + {"verbose", 0, NULL, 'v'}, + {"interactive", 0, NULL, 'i'}, + {NULL, 0, NULL, 0} + }; + + while ((i = getopt_long(argc, argv, "vi", opts, NULL)) != -1) { + switch (i) { + case 'v': + verbose = 1; + break; + case 'i': + interactive = 1; + break; + case 'h': + default:{ + usage(argv[0]); + exit(1); + } + } + } + + if (do_tests(interactive, verbose)) + return -1; + + return 0; +}
diff --git a/selinux/libsemanage/tests/nc_sort_malformed b/selinux/libsemanage/tests/nc_sort_malformed new file mode 100644 index 0000000..85a2d46 --- /dev/null +++ b/selinux/libsemanage/tests/nc_sort_malformed
@@ -0,0 +1,25 @@ +pre *mangle +pre :PREROUTING ACCEPT [0:0] +pre :INPUT ACCEPT [0:0] +pre :FORWARD ACCEPT [0:0] +pre :OUTPUT ACCEPT [0:0] +pre :POSTROUTING ACCEPT [0:0] +pre :selinux_input - [0:0] +pre :selinux_output - [0:0] +pre :selinux_new_input - [0:0] +pre :selinux_new_output - [0:0] +pre -A INPUT -j selinux_input +pre -A OUTPUT -j selinux_output +pre -A selinux_input -m state --state NEW -j selinux_new_input +pre -A selinux_input -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +pre -A selinux_output -m state --state NEW -j selinux_new_output +pre -A selinux_output -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +pre -A selinux_new_input -j SECMARK --selctx system_u:object_r:server_packet_t +base -A selinux_new_input -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_server_packet_t +-A selinux_new_input -j CONNSECMARK --save +post -A selinux_new_input -j RETURN +pre -A selinux_new_output -j SECMARK --selctx system_u:object_r:client_packet_t +module -A selinux_new_output -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_client_packet_t +post -A selinux_new_output -j CONNSECMARK --save +post -A selinux_new_output -j RETURN +post COMMIT
diff --git a/selinux/libsemanage/tests/nc_sort_sorted b/selinux/libsemanage/tests/nc_sort_sorted new file mode 100644 index 0000000..5317a93 --- /dev/null +++ b/selinux/libsemanage/tests/nc_sort_sorted
@@ -0,0 +1,25 @@ +*mangle +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:selinux_input - [0:0] +:selinux_output - [0:0] +:selinux_new_input - [0:0] +:selinux_new_output - [0:0] +-A INPUT -j selinux_input +-A OUTPUT -j selinux_output +-A selinux_input -m state --state NEW -j selinux_new_input +-A selinux_input -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +-A selinux_output -m state --state NEW -j selinux_new_output +-A selinux_output -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +-A selinux_new_input -j SECMARK --selctx system_u:object_r:server_packet_t +-A selinux_new_output -j SECMARK --selctx system_u:object_r:client_packet_t +-A selinux_new_input -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_server_packet_t +-A selinux_new_output -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_client_packet_t +-A selinux_new_input -j CONNSECMARK --save +-A selinux_new_input -j RETURN +-A selinux_new_output -j CONNSECMARK --save +-A selinux_new_output -j RETURN +COMMIT
diff --git a/selinux/libsemanage/tests/nc_sort_unsorted b/selinux/libsemanage/tests/nc_sort_unsorted new file mode 100644 index 0000000..b399753 --- /dev/null +++ b/selinux/libsemanage/tests/nc_sort_unsorted
@@ -0,0 +1,27 @@ +pre *mangle +pre :PREROUTING ACCEPT [0:0] +pre :INPUT ACCEPT [0:0] +pre :FORWARD ACCEPT [0:0] +pre :OUTPUT ACCEPT [0:0] +pre :POSTROUTING ACCEPT [0:0] +pre :selinux_input - [0:0] +pre :selinux_output - [0:0] +pre :selinux_new_input - [0:0] +pre :selinux_new_output - [0:0] +# a comment +pre -A INPUT -j selinux_input +pre -A OUTPUT -j selinux_output +pre -A selinux_input -m state --state NEW -j selinux_new_input +pre -A selinux_input -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +pre -A selinux_output -m state --state NEW -j selinux_new_output + # another comment +pre -A selinux_output -m state --state RELATED,ESTABLISHED -j CONNSECMARK --restore +base-A selinux_new_input -j SECMARK --selctx system_u:object_r:server_packet_t +module -A selinux_new_input -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_server_packet_t +post -A selinux_new_input -j CONNSECMARK --save +post -A selinux_new_input -j RETURN +base -A selinux_new_output -j SECMARK --selctx system_u:object_r:client_packet_t +module -A selinux_new_output -p tcp --dport 80 -j SECMARK --selctx system_u:object_r:http_client_packet_t +post -A selinux_new_output -j CONNSECMARK --save +post -A selinux_new_output -j RETURN +post COMMIT
diff --git a/selinux/libsemanage/tests/test_semanage_store.c b/selinux/libsemanage/tests/test_semanage_store.c new file mode 100644 index 0000000..b324d50 --- /dev/null +++ b/selinux/libsemanage/tests/test_semanage_store.c
@@ -0,0 +1,375 @@ +/* Authors: Christopher Ashworth <cashworth@tresys.com> + * Caleb Case <ccase@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* The purpose of this file is to provide unit tests of the functions in: + * + * libsemanage/src/semanage_store.c + * + */ + +#include "handle.h" +#include "semanage_store.h" + +#include "utilities.h" +#include "test_semanage_store.h" + +#include <libgen.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <CUnit/Basic.h> + +semanage_handle_t *sh = NULL; +const char *rootpath = "./test-policy"; +const char *polpath = "./test-policy/store/"; +const char *readlockpath = "./test-policy/store/semanage.read.LOCK"; +const char *translockpath = "./test-policy/store/semanage.trans.LOCK"; +const char *actpath = "./test-policy/store/active"; +const char *modpath = "./test-policy/store/active/modules"; + +/* The suite initialization function. + * Returns zero on success, non-zero otherwise. + */ +int semanage_store_test_init(void) +{ + int err; + + /* create directories */ + err = mkdir(rootpath, S_IRUSR | S_IWUSR | S_IXUSR); + if (err != 0) + return -1; + + err = mkdir(polpath, S_IRUSR | S_IWUSR | S_IXUSR); + if (err != 0) + return -1; + + err = mkdir(actpath, S_IRUSR | S_IWUSR | S_IXUSR); + if (err != 0) + return -1; + + err = mkdir(modpath, S_IRUSR | S_IWUSR | S_IXUSR); + if (err != 0) + return -1; + + /* initialize the handle */ + sh = semanage_handle_create(); + if (sh == NULL) + return -1; + + /* hide error messages */ + sh->msg_callback = test_msg_handler; + + /* use our own policy store */ + free(sh->conf->store_path); + sh->conf->store_path = strdup("store"); + + /* initialize paths */ + err = semanage_check_init(sh, rootpath); + if (err != 0) + return -1; + + return 0; +} + +/* The suite cleanup function. + * Returns zero on success, non-zero otherwise. + */ +int semanage_store_test_cleanup(void) +{ + int err; + + /* remove the test policy directories */ + err = rmdir(modpath); + if (err != 0) + return -1; + + err = rmdir(actpath); + if (err != 0) + return -1; + + err = rmdir(polpath); + if (err != 0) + return -1; + + err = rmdir(rootpath); + if (err != 0) + return -1; + + /* cleanup the handle */ + semanage_handle_destroy(sh); + return 0; +} + +/* Adds all the tests needed for this suite. + */ +int semanage_store_add_tests(CU_pSuite suite) +{ + if (NULL == + CU_add_test(suite, "semanage_store_access_check", + test_semanage_store_access_check)) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if (NULL == + CU_add_test(suite, "semanage_get_lock", test_semanage_get_lock)) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if (NULL == + CU_add_test(suite, "semanage_nc_sort", test_semanage_nc_sort)) { + CU_cleanup_registry(); + return CU_get_error(); + } + + return 0; +} + +/* Tests the semanage_store_access_check function in semanage_store.c + */ +void test_semanage_store_access_check(void) +{ + int err; + + /* create lock file */ + err = mknod(readlockpath, S_IRUSR | S_IWUSR, S_IFREG); + + /* check with permissions 000 */ + err = chmod(modpath, 0); + CU_ASSERT(err == 0); + err = chmod(readlockpath, 0); + CU_ASSERT(err == 0); + err = chmod(polpath, 0); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == -1); + + /* check with permissions 500 */ + err = chmod(polpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(readlockpath, S_IRUSR); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == SEMANAGE_CAN_READ); + + /* check with permissions 700 */ + err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(readlockpath, S_IRUSR | S_IWUSR); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == SEMANAGE_CAN_WRITE); + + /* check with lock file 000 and others 500 */ + err = chmod(polpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(readlockpath, 0); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == 0); + + /* check with lock file 000 and others 700 */ + err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(readlockpath, 0); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == 0); + + /* remove lock file */ + err = remove(readlockpath); + CU_ASSERT(err == 0); + + /* check with no lock file and 000 */ + err = chmod(modpath, 0); + CU_ASSERT(err == 0); + err = chmod(polpath, 0); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == -1); + + /* check with no lock file and 500 */ + err = chmod(polpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == 0); + + /* check with no lock file but write in polpath */ + err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == SEMANAGE_CAN_READ); + + /* check with no lock file and 700 */ + err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR); + CU_ASSERT(err == 0); + + err = semanage_store_access_check(); + CU_ASSERT(err == SEMANAGE_CAN_WRITE); +} + +/* Tests the semanage_get_lock functions in semanage_store.c + */ +void test_semanage_get_lock(void) +{ + int err; + + /* attempt to get an active lock */ + err = semanage_get_active_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to get the lock again */ + err = semanage_get_active_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to release the active lock */ + semanage_release_active_lock(sh); + + /* attempt to get an active lock */ + err = semanage_get_active_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to release the active lock */ + semanage_release_active_lock(sh); + + /* attempt to get a trans lock */ + err = semanage_get_trans_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to get the lock again */ + err = semanage_get_trans_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to release the trans lock */ + semanage_release_trans_lock(sh); + + /* attempt to get a trans lock */ + err = semanage_get_trans_lock(sh); + CU_ASSERT(err == 0); + + /* attempt to release the trans lock */ + semanage_release_trans_lock(sh); + + /* remove the lock files */ + err = remove(readlockpath); + CU_ASSERT(err == 0); + err = remove(translockpath); + CU_ASSERT(err == 0); +} + +/* Tests the semanage_nc_sort function in semanage_store.c + */ +void test_semanage_nc_sort(void) +{ + char *source_buf, *sorted_buf = NULL, *good_buf, *bad_buf; + size_t source_buf_len, sorted_buf_len, good_buf_len, bad_buf_len; + int sourcefd, goodfd, badfd, err; + struct stat sb; + + /* open source file */ + sourcefd = open("nc_sort_unsorted", O_RDONLY); + if (sourcefd < 0) { + CU_FAIL("Missing nc_sort_unsorted test file."); + return; + } + fstat(sourcefd, &sb); + source_buf_len = sb.st_size; + source_buf = + (char *)mmap(NULL, source_buf_len, PROT_READ, MAP_PRIVATE, sourcefd, + 0); + + /* open good result file */ + goodfd = open("nc_sort_sorted", O_RDONLY); + if (goodfd < 0) { + CU_FAIL("Missing nc_sort_sorted test file."); + goto out2; + } + fstat(goodfd, &sb); + good_buf_len = sb.st_size; + good_buf = + (char *)mmap(NULL, good_buf_len, PROT_READ, MAP_PRIVATE, goodfd, 0); + + /* open malformed source file (missing priorities) */ + badfd = open("nc_sort_malformed", O_RDONLY); + if (badfd < 0) { + CU_FAIL("Missing nc_sort_malformed test file."); + goto out1; + } + fstat(badfd, &sb); + bad_buf_len = sb.st_size; + bad_buf = + (char *)mmap(NULL, bad_buf_len, PROT_READ, MAP_PRIVATE, badfd, 0); + + /* sort test file */ + err = + semanage_nc_sort(sh, source_buf, source_buf_len, &sorted_buf, + &sorted_buf_len); + CU_ASSERT_FALSE(err); + CU_ASSERT_STRING_EQUAL(sorted_buf, good_buf); + + /* reset for reuse in next test */ + free(sorted_buf); + sorted_buf = NULL; + + /* sort malformed source file */ + err = + semanage_nc_sort(sh, bad_buf, bad_buf_len, &sorted_buf, + &sorted_buf_len); + CU_ASSERT_EQUAL(err, -1); + + free(sorted_buf); + + munmap(bad_buf, bad_buf_len); + close(badfd); + out1: + munmap(good_buf, good_buf_len); + close(goodfd); + out2: + munmap(source_buf, source_buf_len); + close(sourcefd); +}
diff --git a/selinux/libsemanage/tests/test_semanage_store.h b/selinux/libsemanage/tests/test_semanage_store.h new file mode 100644 index 0000000..3225497 --- /dev/null +++ b/selinux/libsemanage/tests/test_semanage_store.h
@@ -0,0 +1,34 @@ +/* Authors: Christopher Ashworth <cashworth@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TEST_SEMANAGE_STORE_H__ +#define __TEST_SEMANAGE_STORE_H__ + +#include <CUnit/Basic.h> + +int semanage_store_test_init(void); +int semanage_store_test_cleanup(void); +int semanage_store_add_tests(CU_pSuite suite); + +void test_semanage_store_access_check(void); +void test_semanage_get_lock(void); +void test_semanage_nc_sort(void); + +#endif
diff --git a/selinux/libsemanage/tests/test_utilities.c b/selinux/libsemanage/tests/test_utilities.c new file mode 100644 index 0000000..32cc33c --- /dev/null +++ b/selinux/libsemanage/tests/test_utilities.c
@@ -0,0 +1,285 @@ +/* Authors: Mark Goldman <mgoldman@tresys.com> + * + * Copyright (C) 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 + */ + +/* The purpose of this file is to provide unit tests of the functions in: + * + * libsemanage/src/utilities.c + * + */ + +#include <CUnit/Basic.h> +#include <CUnit/Console.h> +#include <CUnit/TestDB.h> + +#include <utilities.h> +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +void test_semanage_is_prefix(void); +void test_semanage_split_on_space(void); +void test_semanage_split(void); +void test_semanage_list(void); +void test_semanage_str_count(void); +void test_semanage_rtrim(void); +void test_semanage_findval(void); +void test_slurp_file_filter(void); + +char fname[] = { + 'T', 'E', 'S', 'T', '_', 'T', 'E', 'M', 'P', '_', 'X', 'X', 'X', 'X', + 'X', 'X', '\0' +}; +int fd; +FILE *fptr; + +int semanage_utilities_test_init(void) +{ + fd = mkstemp(fname); + + if (fd < 0) { + perror("test_semanage_findval: "); + CU_FAIL_FATAL + ("Error opening temporary file, test cannot start."); + } + + fptr = fdopen(fd, "w+"); + if (!fptr) { + perror("test_semanage_findval file: "); + CU_FAIL_FATAL("Error opening file stream, test cannot start."); + } + + fprintf(fptr, "one\ntwo\nthree\nsigma=foo\n#boo\n#bar\n"); + + rewind(fptr); + return 0; +} + +int semanage_utilities_test_cleanup(void) +{ + unlink(fname); + return 0; +} + +int semanage_utilities_add_tests(CU_pSuite suite) +{ + if (NULL == CU_add_test(suite, "semanage_is_prefix", + test_semanage_is_prefix)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_split_on_space", + test_semanage_split_on_space)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_split", test_semanage_split)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_list", test_semanage_list)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_str_count", + test_semanage_str_count)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_rtrim", test_semanage_rtrim)) { + goto err; + } + if (NULL == CU_add_test(suite, "semanage_findval", + test_semanage_findval)) { + goto err; + } + if (NULL == CU_add_test(suite, "slurp_file_filter", + test_slurp_file_filter)) { + goto err; + } + return 0; + err: + CU_cleanup_registry(); + return CU_get_error(); +} + +void test_semanage_is_prefix(void) +{ + char *str = "some string"; + char *pre = "some"; + char *not_pre = "not this"; + + CU_ASSERT_TRUE(semanage_is_prefix(str, pre)); + CU_ASSERT_TRUE(semanage_is_prefix(str, "")); + CU_ASSERT_TRUE(semanage_is_prefix(str, NULL)); + CU_ASSERT_FALSE(semanage_is_prefix(str, not_pre)); +} + +void test_semanage_split_on_space(void) +{ + char *str = strdup("foo bar baz"); + char *temp; + + if (!str) { + CU_FAIL + ("semanage_split_on_space: unable to perform test, no memory"); + } + temp = semanage_split_on_space(str); + if (strncmp(temp, "bar", 3)) { + CU_FAIL("semanage_split_on_space: token did not match"); + } + temp = semanage_split_on_space(temp); + if (strncmp(temp, "baz", 3)) { + CU_FAIL("semanage_split_on_space: token did not match"); + } + temp = semanage_split_on_space(temp); + if (strcmp(temp, "")) { + CU_FAIL("semanage_split_on_space: token did not match"); + } + + free(str); +} + +void test_semanage_split(void) +{ + char *str = strdup("foo1 foo2 foo:bar"); + char *temp; + + if (!str) { + CU_FAIL + ("semanage_split_on_space: unable to perform test, no memory"); + return; + } + temp = semanage_split(str, NULL); + CU_ASSERT_NSTRING_EQUAL(temp, "foo2", 4); + temp = semanage_split(temp, ""); + CU_ASSERT_NSTRING_EQUAL(temp, "foo", 3); + temp = semanage_split(temp, ":"); + CU_ASSERT_NSTRING_EQUAL(temp, "bar", 3); + + free(str); +} + +void test_semanage_list(void) +{ + semanage_list_t *list = NULL; + semanage_list_t *ptr = NULL; + char *temp = NULL; + int retval = 0; + + CU_ASSERT_FALSE(semanage_list_push(&list, "foo")); + CU_ASSERT_PTR_NOT_NULL(list); + CU_ASSERT_FALSE(semanage_list_push(&list, "bar")); + CU_ASSERT_FALSE(semanage_list_push(&list, "gonk")); + CU_ASSERT_FALSE(semanage_list_push(&list, "zebra")); + + for (ptr = list; ptr; ptr = ptr->next) + retval++; + CU_ASSERT_EQUAL(retval, 4); + + temp = semanage_list_pop(&list); + CU_ASSERT_STRING_EQUAL(temp, "zebra"); + CU_ASSERT_FALSE(semanage_list_push(&list, temp)); + free(temp); + temp = NULL; + + retval = 0; + for (ptr = list; ptr; ptr = ptr->next) + retval++; + CU_ASSERT_EQUAL(retval, 4); + + retval = semanage_list_sort(&list); + if (retval) { + CU_FAIL + ("semanage_list_sort: error unrelated to sort (memory?)"); + goto past_sort; + } + CU_ASSERT_STRING_EQUAL(list->data, "bar"); + CU_ASSERT_STRING_EQUAL(list->next->data, "foo"); + CU_ASSERT_STRING_EQUAL(list->next->next->data, "gonk"); + CU_ASSERT_STRING_EQUAL(list->next->next->next->data, "zebra"); + + past_sort: + ptr = semanage_list_find(list, "zebra"); + CU_ASSERT_PTR_NOT_NULL(ptr); + ptr = semanage_list_find(list, "bogus"); + CU_ASSERT_PTR_NULL(ptr); + + semanage_list_destroy(&list); + CU_ASSERT_PTR_NULL(list); +} + +void test_semanage_str_count(void) +{ + char *test_string = "abaababbaaaba"; + + CU_ASSERT_EQUAL(semanage_str_count(test_string, 'z'), 0); + CU_ASSERT_EQUAL(semanage_str_count(test_string, 'a'), 8); + CU_ASSERT_EQUAL(semanage_str_count(test_string, 'b'), 5); +} + +void test_semanage_rtrim(void) +{ + char *str = strdup("/blah/foo/bar/baz/"); + + CU_ASSERT_PTR_NOT_NULL_FATAL(str); + + semanage_rtrim(str, 'Q'); + CU_ASSERT_STRING_EQUAL(str, "/blah/foo/bar/baz/"); + semanage_rtrim(str, 'a'); + CU_ASSERT_STRING_EQUAL(str, "/blah/foo/bar/b"); + semanage_rtrim(str, '/'); + CU_ASSERT_STRING_EQUAL(str, "/blah/foo/bar"); +} + +void test_semanage_findval(void) +{ + char *tok; + if (!fptr) { + CU_FAIL_FATAL("Temporary file was not created, aborting test."); + } + tok = semanage_findval(fname, "one", NULL); + CU_ASSERT_STRING_EQUAL(tok, ""); + rewind(fptr); + tok = semanage_findval(fname, "one", ""); + CU_ASSERT_STRING_EQUAL(tok, ""); + free(tok); + rewind(fptr); + tok = semanage_findval(fname, "sigma", "="); + CU_ASSERT_STRING_EQUAL(tok, "foo"); +} + +int PREDICATE(const char *str) +{ + return semanage_is_prefix(str, "#"); +} + +void test_slurp_file_filter(void) +{ + semanage_list_t *data, *tmp; + int cnt = 0; + + if (!fptr) { + CU_FAIL_FATAL("Temporary file was not created, aborting test."); + } + rewind(fptr); + data = semanage_slurp_file_filter(fptr, PREDICATE); + CU_ASSERT_PTR_NOT_NULL_FATAL(data); + for (tmp = data; tmp; tmp = tmp->next) + cnt++; + CU_ASSERT_EQUAL(cnt, 2); + + semanage_list_destroy(&data); +}
diff --git a/selinux/libsemanage/tests/test_utilities.h b/selinux/libsemanage/tests/test_utilities.h new file mode 100644 index 0000000..4c95a68 --- /dev/null +++ b/selinux/libsemanage/tests/test_utilities.h
@@ -0,0 +1,5 @@ +#include <CUnit/Basic.h> + +int semanage_utilities_test_init(void); +int semanage_utilities_test_cleanup(void); +int semanage_utilities_add_tests(CU_pSuite suite);
diff --git a/selinux/libsemanage/tests/utilities.c b/selinux/libsemanage/tests/utilities.c new file mode 100644 index 0000000..7cc726c --- /dev/null +++ b/selinux/libsemanage/tests/utilities.c
@@ -0,0 +1,32 @@ +/* Authors: Christopher Ashworth <cashworth@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* The purpose of this file is to provide some functions commonly needed + * by our unit tests. + */ + +#include "utilities.h" + +/* Silence any error output caused by our tests + * by using this dummy function to catch messages. + */ +void test_msg_handler(void *varg, + semanage_handle_t * handle, const char *fmt, ...) +{ +}
diff --git a/selinux/libsemanage/tests/utilities.h b/selinux/libsemanage/tests/utilities.h new file mode 100644 index 0000000..781867d --- /dev/null +++ b/selinux/libsemanage/tests/utilities.h
@@ -0,0 +1,23 @@ +/* Authors: Christopher Ashworth <cashworth@tresys.com> + * + * Copyright (C) 2006 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "handle.h" + +void test_msg_handler(void *varg, semanage_handle_t * handle, const char *fmt, + ...);
diff --git a/selinux/libsemanage/utils/Makefile b/selinux/libsemanage/utils/Makefile new file mode 100644 index 0000000..725f0ee --- /dev/null +++ b/selinux/libsemanage/utils/Makefile
@@ -0,0 +1,19 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +LIBEXECDIR ?= $(PREFIX)/libexec +SELINUXEXECDIR ?= $(LIBEXECDIR)/selinux/ + +all: + +install: all + -mkdir -p $(SELINUXEXECDIR) + install -m 755 semanage_migrate_store $(SELINUXEXECDIR) + +clean: + +distclean: clean + +indent: + +relabel: +
diff --git a/selinux/libsemanage/utils/semanage_migrate_store b/selinux/libsemanage/utils/semanage_migrate_store new file mode 100755 index 0000000..0ebd285 --- /dev/null +++ b/selinux/libsemanage/utils/semanage_migrate_store
@@ -0,0 +1,287 @@ +#!/usr/bin/python -E + + +from __future__ import print_function +import os +import errno +import shutil +import sys +from optparse import OptionParser + +import ctypes + +sepol = ctypes.cdll.LoadLibrary('libsepol.so.1') + +try: + import selinux + import semanage +except: + print("You must install libselinux-python and libsemanage-python before running this tool", file=sys.stderr) + exit(1) + + +def copy_file(src, dst): + if DEBUG: + print("copying %s to %s" % (src, dst)) + try: + shutil.copy(src, dst) + except OSError as the_err: + (err, strerr) = the_err.args + print("Could not copy %s to %s, %s" %(src, dst, strerr), file=sys.stderr) + exit(1) + + +def create_dir(dst, mode): + if DEBUG: print("Making directory %s" % dst) + try: + os.makedirs(dst, mode) + except OSError as the_err: + (err, stderr) = the_err.args + if err == errno.EEXIST: + pass + else: + print("Error creating %s" % dst, file=sys.stderr) + exit(1) + + +def create_file(dst): + if DEBUG: print("Making file %s" % dst) + try: + open(dst, 'a').close() + except OSError as the_err: + (err, stderr) = the_err.args + print("Error creating %s" % dst, file=sys.stderr) + exit(1) + + +def copy_module(store, name, base): + if DEBUG: print("Install module %s" % name) + (file, ext) = os.path.splitext(name) + if ext != ".pp": + # Stray non-pp file in modules directory, skip + print("warning: %s has invalid extension, skipping" % name, file=sys.stderr) + return + try: + if base: + root = oldstore_path(store) + else: + root = oldmodules_path(store) + + bottomdir = bottomdir_path(store) + + os.mkdir("%s/%s" % (bottomdir, file)) + + copy_file(os.path.join(root, name), "%s/%s/hll" % (bottomdir, file)) + + # This is the ext file that will eventually be used to choose a compiler + efile = open("%s/%s/lang_ext" % (bottomdir, file), "w+", 0o600) + efile.write("pp") + efile.close() + + except: + print("Error installing module %s" % name, file=sys.stderr) + exit(1) + + +def disable_module(file, name, disabledmodules): + if DEBUG: print("Disabling %s" % name) + (disabledname, disabledext) = os.path.splitext(file) + create_file("%s/%s" % (disabledmodules, disabledname)) + +def migrate_store(store): + + oldstore = oldstore_path(store); + oldmodules = oldmodules_path(store); + disabledmodules = disabledmodules_path(store); + newstore = newstore_path(store); + newmodules = newmodules_path(store); + bottomdir = bottomdir_path(store); + + print("Migrating from %s to %s" % (oldstore, newstore)) + + # Build up new directory structure + create_dir("%s/%s" % (newroot_path(), store), 0o755) + create_dir(newstore, 0o700) + create_dir(newmodules, 0o700) + create_dir(bottomdir, 0o700) + create_dir(disabledmodules, 0o700) + + # Special case for base since it was in a different location + copy_module(store, "base.pp", 1) + + # Dir structure built, start copying files + for root, dirs, files in os.walk(oldstore): + if root == oldstore: + # This is the top level directory, need to move + for name in files: + # Check to see if it is in TOPPATHS and copy if so + if name in TOPPATHS: + if name == "seusers": + newname = "seusers.local" + else: + newname = name + copy_file(os.path.join(root, name), os.path.join(newstore, newname)) + + elif root == oldmodules: + # This should be the modules directory + for name in files: + (file, ext) = os.path.splitext(name) + if name == "base.pp": + print("Error installing module %s, name conflicts with base" % name, file=sys.stderr) + exit(1) + elif ext == ".disabled": + disable_module(file, name, disabledmodules) + else: + copy_module(store, name, 0) + +def rebuild_policy(): + # Ok, the modules are loaded, lets try to rebuild the policy + print("Attempting to rebuild policy from %s" % newroot_path()) + + curstore = selinux.selinux_getpolicytype()[1] + + handle = semanage.semanage_handle_create() + if not handle: + print("Could not create semanage handle", file=sys.stderr) + exit(1) + + semanage.semanage_select_store(handle, curstore, semanage.SEMANAGE_CON_DIRECT) + + if not semanage.semanage_is_managed(handle): + semanage.semanage_handle_destroy(handle) + print("SELinux policy is not managed or store cannot be accessed.", file=sys.stderr) + exit(1) + + rc = semanage.semanage_access_check(handle) + if rc < semanage.SEMANAGE_CAN_WRITE: + semanage.semanage_handle_destroy(handle) + print("Cannot write to policy store.", file=sys.stderr) + exit(1) + + rc = semanage.semanage_connect(handle) + if rc < 0: + semanage.semanage_handle_destroy(handle) + print("Could not establish semanage connection", file=sys.stderr) + exit(1) + + semanage.semanage_set_rebuild(handle, 1) + + rc = semanage.semanage_begin_transaction(handle) + if rc < 0: + semanage.semanage_handle_destroy(handle) + print("Could not begin transaction", file=sys.stderr) + exit(1) + + rc = semanage.semanage_commit(handle) + if rc < 0: + print("Could not commit transaction", file=sys.stderr) + + semanage.semanage_handle_destroy(handle) + + +def oldroot_path(): + return "%s/etc/selinux" % ROOT + +def oldstore_path(store): + return "%s/%s/modules/active" % (oldroot_path(), store) + +def oldmodules_path(store): + return "%s/modules" % oldstore_path(store) + +def disabledmodules_path(store): + return "%s/disabled" % newmodules_path(store) + +def newroot_path(): + return "%s%s" % (ROOT, PATH) + +def newstore_path(store): + return "%s/%s/active" % (newroot_path(), store) + +def newmodules_path(store): + return "%s/modules" % newstore_path(store) + +def bottomdir_path(store): + return "%s/%s" % (newmodules_path(store), PRIORITY) + + +if __name__ == "__main__": + + parser = OptionParser() + parser.add_option("-p", "--priority", dest="priority", default="100", + help="Set priority of modules in new store (default: 100)") + parser.add_option("-s", "--store", dest="store", default=None, + help="Store to read from and write to") + parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, + help="Output debug information") + parser.add_option("-c", "--clean", dest="clean", action="store_true", default=False, + help="Clean old modules directory after migrate (default: no)") + parser.add_option("-n", "--norebuild", dest="norebuild", action="store_true", default=False, + help="Disable rebuilding policy after migration (default: no)") + parser.add_option("-P", "--path", dest="path", + help="Set path for the policy store (default: /var/lib/selinux)") + parser.add_option("-r", "--root", dest="root", + help="Set an alternative root for the migration (default: /)") + + (options, args) = parser.parse_args() + + DEBUG = options.debug + PRIORITY = options.priority + TYPE = options.store + CLEAN = options.clean + NOREBUILD = options.norebuild + PATH = options.path + if PATH is None: + PATH = "/var/lib/selinux" + + ROOT = options.root + if ROOT is None: + ROOT = "" + + # List of paths that go in the active 'root' + TOPPATHS = [ + "commit_num", + "ports.local", + "interfaces.local", + "nodes.local", + "booleans.local", + "file_contexts.local", + "seusers", + "users.local", + "users_extra", + "users_extra.local", + "disable_dontaudit", + "preserve_tunables", + "policy.kern", + "file_contexts", + "homedir_template"] + + + create_dir(newroot_path(), 0o755) + + stores = None + if TYPE is not None: + stores = [TYPE] + else: + stores = os.listdir(oldroot_path()) + + # find stores in oldroot and migrate them to newroot if necessary + for store in stores: + if not os.path.isdir(oldmodules_path(store)): + # already migrated or not an selinux store + continue + + if os.path.isdir(newstore_path(store)): + # store has already been migrated, but old modules dir still exits + print("warning: Policy type %s has already been migrated, but modules still exist in the old store. Skipping store." % store, file=sys.stderr) + continue + + migrate_store(store) + + if CLEAN is True: + def remove_error(function, path, execinfo): + print("warning: Unable to remove old store modules directory %s. Cleaning failed." % oldmodules_path(store), file=sys.stderr) + shutil.rmtree(oldmodules_path(store), onerror=remove_error) + + if NOREBUILD is False: + rebuild_policy() +
diff --git a/selinux/libsepol/Android.mk b/selinux/libsepol/Android.mk new file mode 100644 index 0000000..9507496 --- /dev/null +++ b/selinux/libsepol/Android.mk
@@ -0,0 +1,137 @@ +LOCAL_PATH:= $(call my-dir) + +common_src_files := \ + src/assertion.c \ + src/avrule_block.c \ + src/avtab.c \ + src/boolean_record.c \ + src/booleans.c \ + src/conditional.c \ + src/constraint.c \ + src/context.c \ + src/context_record.c \ + src/debug.c \ + src/ebitmap.c \ + src/expand.c \ + src/genbools.c \ + src/genusers.c \ + src/handle.c \ + src/hashtab.c \ + src/hierarchy.c \ + src/iface_record.c \ + src/interfaces.c \ + src/link.c \ + src/mls.c \ + src/module.c \ + src/module_to_cil.c \ + src/node_record.c \ + src/nodes.c \ + src/polcaps.c \ + src/policydb.c \ + src/policydb_convert.c \ + src/policydb_public.c \ + src/port_record.c \ + src/ports.c \ + src/roles.c \ + src/services.c \ + src/sidtab.c \ + src/symtab.c \ + src/user_record.c \ + src/users.c \ + src/util.c \ + src/write.c + +cil_src_files := \ + cil/src/cil_binary.c \ + cil/src/cil_build_ast.c \ + cil/src/cil.c \ + cil/src/cil_copy_ast.c \ + cil/src/cil_find.c \ + cil/src/cil_fqn.c \ + cil/src/cil_lexer.l \ + cil/src/cil_list.c \ + cil/src/cil_log.c \ + cil/src/cil_mem.c \ + cil/src/cil_parser.c \ + cil/src/cil_policy.c \ + cil/src/cil_post.c \ + cil/src/cil_reset_ast.c \ + cil/src/cil_resolve_ast.c \ + cil/src/cil_stack.c \ + cil/src/cil_strpool.c \ + cil/src/cil_symtab.c \ + cil/src/cil_tree.c \ + cil/src/cil_verify.c + +common_cflags := \ + -D_GNU_SOURCE \ + -Wall -W -Wundef \ + -Wshadow -Wmissing-noreturn \ + -Wmissing-format-attribute + +common_includes := \ + $(LOCAL_PATH)/include/ \ + $(LOCAL_PATH)/src/ \ + $(LOCAL_PATH)/cil/include/ \ + $(LOCAL_PATH)/cil/src/ \ + +## +# "-x c" forces the lex/yacc files to be compiled as c the build system +# otherwise forces them to be c++. Need to also add an explicit -std because the +# build system will soon default C++ to -std=c++11. +yacc_flags := -x c -std=gnu89 + +## +# libsepol.so +# +include $(CLEAR_VARS) + +LOCAL_MODULE := libsepol +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_CPPFLAGS := $(yacc_flags) +LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +include $(BUILD_HOST_SHARED_LIBRARY) + +## +# libsepol.a +# +include $(CLEAR_VARS) + +LOCAL_MODULE := libsepol +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_CPPFLAGS := $(yacc_flags) +LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +include $(BUILD_HOST_STATIC_LIBRARY) + +## +# chkcon +# +include $(CLEAR_VARS) + +LOCAL_MODULE := chkcon +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_SRC_FILES := utils/chkcon.c +LOCAL_SHARED_LIBRARIES := libsepol + +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libsepol +LOCAL_MODULE_TAGES := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_CFLAGS := $(common_cflags) +LOCAL_SRC_FILES := $(common_src_files) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +include $(BUILD_STATIC_LIBRARY)
diff --git a/selinux/libsepol/COPYING b/selinux/libsepol/COPYING new file mode 100644 index 0000000..8add30a --- /dev/null +++ b/selinux/libsepol/COPYING
@@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +
diff --git a/selinux/libsepol/ChangeLog b/selinux/libsepol/ChangeLog new file mode 100644 index 0000000..95e56d4 --- /dev/null +++ b/selinux/libsepol/ChangeLog
@@ -0,0 +1,886 @@ + * Fix neverallowxperm checking on attributes, from Jeff Vander Stoep. + * Remove libsepol.map when cleaning, from Nicolas Iooss. + * Add high-level language line marking support to CIL, from James Carter. + * Change logic of bounds checking to match change in kernel, from James Carter. + * Fix multiple spelling errors, from Laurent Bigonville. + * Only apply bounds checking to source types in rules, from Stephen Smalley. + * Fix CIL and not add an attribute as a type in the attr_type_map, from James Carter + * Build policy on systems not supporting DCCP protocol, from Richard Haines. + * Fix extended permissions neverallow checking, from Jeff Vander Stoep. + * Fix CIL neverallow and bounds checking, from James Carter + * Android.mk: Add -D_GNU_SOURCE to common_cflags, from Nick Kralevich. + * Add support for portcon dccp protocol, from Richard Haines + * Fix bug in CIL when resetting classes, from Steve Lawrence + +2.5 2016-02-23 + * Fix unused variable annotations, from Nicolas Iooss. + * Fix uninitialized variable in CIL, from Nicolas Iooss. + * Validate extended avrules and permissionxs in CIL, from Steve Lawrence. + * Add support in CIL for neverallowx, from Steve Lawrence. + * Fully expand neverallowxperm rules, from Richard Haines. + * Add support for unordered classes to CIL, from Yuli Khodorkovskiy. + * Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep. + * Improve CIL block and macro call recursion detection, from Steve Lawrence + * Fix CIL uninitialized false positive in cil_binary, from Yuli Khodorkovskiy + * Provide error in CIL if classperms are empty, from Yuli Khodorkovskiy + * Add userattribute{set} functionality to CIL, from Yuli Khodorkovskiy + * fix CIL blockinherit copying segfault and add macro restrictions, from Steve Lawrence + * fix CIL NULL pointer dereference when copying classpermission/set, from Steve Lawrence + * Add CIL support for ioctl whitelists, from Steve Lawrence + * Fix memory leak when destroying avtab, from Steve Lawrence + * Replace sscanf in module_to_cil, from Yuli Khodorkovskiy. + * Improve CIL resolution error messages, from Steve Lawrence + * Fix policydb_read for policy versions < 24, from Stephen Smalley. + * Added CIL bounds checking and refactored CIL Neverallow checking, from James Carter + * Refactored libsepol Neverallow and bounds (hierarchy) checking, from James Carter + * Treat types like an attribute in the attr_type_map, from James Carter + * Add new ebitmap function named ebitmap_match_any(), from James Carter + * switch operations to extended perms, from Jeff Vander Stoep. + * Write auditadm_r and secadm_r roles to base module when writing CIL, from Steve Lawrence + * Fix module to CIL to only associate declared roleattributes with in-scope types, from Steve Lawrence + * Don't allow categories/sensitivities inside blocks in CIL, from Yuli Khodorkovskiy. + * Replace fmemopen() with internal function in libsepol, from James Carter. + * Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy. + * Binary modules do not support ioctl rules, from Stephen Smalley. + * Add support for ioctl command whitelisting, from Jeff Vander Stoep. + * Don't use symbol versioning for static object files, from Yuli Khodorkovskiy. + * Add sepol_module_policydb_to_cil(), sepol_module_package_to_cil(), and sepol_ppfile_to_module_package(), from James Carter. + * Move secilc out of libsepol, from Yuli Khodorkovskiy. + * fix building Xen policy with devicetreecon, and add devicetreecon + CIL documentation, from Richard Haines. + * bool_copy_callback set state on creation, from Thomas Hurd. + * Add device tree ocontext nodes to Xen policy, from Daniel De Graaf. + * Widen Xen IOMEM context entries, from Daniel De Graaf. + * Update CIL documentation, from Richard Haines + * Fix error path in mls_semantic_level_expand(), from Chris PeBenito. + * Fix MacOS X build, from Stephen Smalley. + * Enabling building CIL in Android, from Stephen Smalley. + * Update to latest CIL, includes new name resolution and fixes ordering + issues with blockinherit statements, and bug fixes + +2.4 2015-02-02 + * Remove assumption that SHLIBDIR is ../../ relative to LIBDIR, from Steve + Lawrence + * Fix bugs found by hardened gcc flags, from Nicolas Iooss. + * Build CIL into libsepol. libsepol can be built without CIL by setting the + DISABLE_CIL flag to 'y', from Steve Lawrence + * Add an API function to set target_platform, from Steve Lawrence + * Report all neverallow violations, from Stephen Smalley + * Improve check_assertions performance through hash tweaks from John Brooks. + * Allow libsepol C++ static library on device from Daniel Cashman. + +2.3 2014-05-06 + * Improve error message for name-based transition conflicts. + * Revert libsepol: filename_trans: use some better sorting to compare and merge. + * Report source file and line information for neverallow failures. + * Fix valgrind errors in constraint_expr_eval_reason from Richard Haines. + * Add sepol_validate_transition_reason_buffer function from Richard Haines. + +2.2 2013-10-30 + * Allow constraint denial cause to be determined from Richard Haines. + - Add kernel policy version 29. + - Add modular policy version 17. + - Add sepol_compute_av_reason_buffer(), sepol_string_to_security_class(), sepol_string_to_av_perm(). + * Support overriding Makefile RANLIB from Sven Vermeulen. + * Fix man pages from Laurent Bigonville. + +2.1.9 2013-02-01 + * filename_trans: use some better sorting to compare and merge + * coverity fixes + * implement default type policy syntax + * Fix memory leak issues found by Klocwork + +2.1.8 2012-09-13 + * fix neverallow checking on attributes + * Move context_copy() after switch block in ocontext_copy_*(). + * check for missing initial SID labeling statement. + * Add always_check_network policy capability + * role_fix_callback skips out-of-scope roles during expansion. + +2.1.7 2012-06-28 + * reserve policycapability for redhat testing of ptrace child + * cosmetic changes to make the source easier to read + * prepend instead of append to filename_trans list + * Android/MacOS X build support + +2.1.6 2012-04-23 + * allocate enough space to hold filename in trans rules + +2.1.5 2012-03-28 + * checkpolicy: implement new default labeling behaviors + +2.1.4 2011-10-03 + * regenerate .pc on VERSION change + * Move ebitmap_* functions from mcstrans to libsepol + * expand: do filename_trans type comparison on mapped representation + +2.1.3 2011-09-15 + * Skip writing role attributes for policy.X and + * Indicate when boolean is indeed a tunable. + * Separate tunable from boolean during compile. + * Write and read TUNABLE flags in related + * Copy and check the cond_bool_datum_t.flags during link. + * Permanently discard disabled branches of tunables in + * Skip tunable identifier and cond_node_t in expansion. + * Create a new preserve_tunables flag + * Preserve tunables when required by semodule program. + * setools expects expand_module_avrules to be an exported + * tree: default make target to all not + +2.1.2 2011-08-03 + * Only call role_fix_callback for base.p_roles during expansion. + * use mapped role number instead of module role number + +2.1.1 2011-08-01 + * Minor fix to reading policy with filename transition rules + +2.1.0 2011-07-27 + * Release, minor version bump + +2.0.46 2011-07-25 + * Add role attribute support by Harry Ciao + +2.0.45 2011-05-02 + * Warn if filename_trans rules are dropped by Steve Lawrence. + +2.0.44 2011-04-13 + * Fixes for new role_transition class field by Eric Paris. + * Add libsepol support for filename_trans rules by Eric Paris. + +2.0.43 2011-04-11 + * Add new class field in role_transition by Harry Ciao. + +2.0.42 2010-12-16 + * Fix compliation under GCC 4.6 by Justin Mattock + +2.0.41 2009-11-18 + * Fixed typo in error message from Manoj Srivastava. + +2.0.40 2009-10-29 + * Add pkgconfig file from Eamon Walsh. + +2.0.39 2009-10-14 + * Add support for building Xen policies from Paul Nuzzi. + +2.0.38 2009-09-01 + * Check last offset in the module package against the file size. + Reported by Manoj Srivastava for bug filed by Max Kellermann. + +2.0.37 2009-07-07 + * Add method to check disable dontaudit flag from Christopher Pardy. + +2.0.36 2009-03-25 + * Fix boolean state smashing from Joshua Brindle. + +2.0.35 2009-02-19 + * Fix alias field in module format, caused by boundary format change + from Caleb Case. + +2.0.34 2008-10-09 + * Add bounds support from KaiGai Kohei. + * Fix invalid aliases bug from Joshua Brindle. + +2.0.33 2008-09-29 + * Revert patch that removed expand_rule. + +2.0.32 2008-07-07 + * Allow require then declare in the source policy from Joshua Brindle. + +2.0.31 2008-06-13 + * Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley. + +2.0.30 2008-06-06 + * Fix endianness bug in the handling of network node addresses from Stephen Smalley. + Only affects big endian platforms. + Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc. + +2.0.29 2008-05-27 + * Merge user and role mapping support from Joshua Brindle. + +2.0.28 2008-05-05 + * Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley. + +2.0.27 2008-04-18 + * Belatedly merge test for policy downgrade from Todd Miller. + +2.0.26 2008-03-24 + * Add permissive domain support from Eric Paris. + +2.0.25 2008-03-04 + * Drop unused ->buffer field from struct policy_file. + +2.0.24 2008-03-04 + * Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller. + +2.0.23 2008-02-28 + * Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley. + +2.0.22 2008-02-28 + * Add support for open_perms policy capability from Eric Paris. + +2.0.21 2008-02-20 + * Fix invalid memory allocation in policydb_index_others() from Jason Tang. + +2.0.20 2008-02-04 + * Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley. + +2.0.19 2008-02-02 + * Add support for consuming avrule_blocks during expansion to reduce + peak memory usage from Joshua Brindle. + +2.0.18 2008-01-02 + * Added support for policy capabilities from Todd Miller. + +2.0.17 2007-12-21 + * Prevent generation of policy.18 with MLS enabled from Todd Miller. + +2.0.16 2007-12-07 + * print module magic number in hex on mismatch, from Todd Miller. + +2.0.15 2007-11-29 + * clarify and reduce neverallow error reporting from Stephen Smalley. + +2.0.14 2007-11-05 + * Reject self aliasing at link time from Stephen Smalley. + +2.0.13 2007-11-05 + * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley. + +2.0.12 2007-10-11 + * Fixed bug in require checking from Stephen Smalley. + * Added user hierarchy checking from Todd Miller. + +2.0.11 2007-09-24 + * Pass CFLAGS to CC even on link command, per Dennis Gilmore. + +2.0.10 2007-09-18 + * Merged support for the handle_unknown policydb flag from Eric Paris. + +2.0.9 2007-08-29 + * Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper. + +2.0.8 2007-08-28 + * Fixed module_package_read_offsets bug introduced by the prior patch. + +2.0.7 2007-08-23 + * Eliminate unaligned accesses from policy reading code from Stephen Smalley. + +2.0.6 2007-08-16 + * Allow dontaudits to be turned off during policy expansion from + Joshua Brindle. + +2.0.5 2007-08-01 + * Fix sepol_context_clone to handle a NULL context correctly. + This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL) + to set the file context entry to "<<none>>". + +2.0.4 2007-06-20 + * Merged error handling patch from Eamon Walsh. + +2.0.3 2007-04-13 + * Merged add boolmap argument to expand_module_avrules() from Chris PeBenito. + +2.0.2 2007-03-30 + * Merged fix from Karl to remap booleans at expand time to + avoid holes in the symbol table. + +2.0.1 2007-02-06 + * Merged libsepol segfault fix from Stephen Smalley for when + sensitivities are required but not present in the base. + +2.0.0 2007-02-01 + * Merged patch to add errcodes.h to libsepol by Karl MacMillan. + +1.16.0 2007-01-18 + * Updated version for stable branch. + +1.15.3 2006-11-27 + * Merged patch to compile wit -fPIC instead of -fpic from + Manoj Srivastava to prevent hitting the global offest table + limit. Patch changed to include libselinux and libsemanage in + addition to libselinux. +1.15.2 2006-10-31 + * Merged fix from Karl MacMillan for a segfault when linking + non-MLS modules with users in them. + +1.15.1 2006-10-24 + * Merged fix for version comparison that was preventing range + transition rules from being written for a version 5 base policy + from Darrel Goeddel. + +1.14 2006-10-17 + * Updated version for release. + +1.12.28 2006-09-28 + * Build libsepol's static object files with -fpic + +1.12.27 2006-09-28 + * Merged mls user and range_transition support in modules + from Darrel Goeddel + +1.12.26 2006-09-05 + * Merged range transition enhancements and user format changes + Darrel Goeddel + +1.12.25 2006-08-24 + * Merged conditionally expand neverallows patch from Jeremy Mowery. + * Merged refactor expander patch from Jeremy Mowery. + +1.12.24 2006-08-03 + * Merged libsepol unit tests from Joshua Brindle. + +1.12.23 2006-08-03 + * Merged symtab datum patch from Karl MacMillan. + +1.12.22 2006-08-03 + * Merged netfilter contexts support from Chris PeBenito. + +1.12.21 2006-07-28 + * Merged helpful hierarchy check errors patch from Joshua Brindle. + +1.12.20 2006-07-25 + * Merged semodule_deps patch from Karl MacMillan. + This adds source module names to the avrule decls. + +1.12.19 2006-06-29 + * Lindent. + +1.12.18 2006-06-26 + * Merged optionals in base take 2 patch set from Joshua Brindle. + +1.12.17 2006-05-30 + * Revert 1.12.16. + +1.12.16 2006-05-30 + * Merged cleaner fix for bool_ids overflow from Karl MacMillan, + replacing the prior patch. + +1.12.15 2006-05-30 + * Merged fixes for several memory leaks in the error paths during + policy read from Serge Hallyn. + +1.12.14 2006-05-25 + * Fixed bool_ids overflow bug in cond_node_find and cond_copy_list, + based on bug report and suggested fix by Cedric Roux. + +1.12.13 2006-05-24 + * Merged sens_copy_callback, check_role_hierarchy_callback, + and node_from_record fixes from Serge Hallyn. + +1.12.12 2006-05-22 + * Added sepol_policydb_compat_net() interface for testing whether + a policy requires the compatibility support for network checks + to be enabled in the kernel. + +1.12.11 2006-05-17 + * Merged patch to initialize sym_val_to_name arrays from Kevin Carr. + Reworked to use calloc in the first place, and converted some other + malloc/memset pairs to calloc calls. + +1.12.10 2006-05-08 + * Merged patch to revert role/user decl upgrade from Karl MacMillan. + +1.12.9 2006-05-08 + * Dropped tests from all Makefile target. + +1.12.8 2006-05-05 + * Merged fix warnings patch from Karl MacMillan. + +1.12.7 2006-05-05 + * Merged libsepol test framework patch from Karl MacMillan. + +1.12.6 2006-04-28 + * Fixed cond_normalize to traverse the entire cond list at link time. + +1.12.5 2006-04-03 + * Merged fix for leak of optional package sections from Ivan Gyurdiev. + +1.12.4 2006-03-29 + * Generalize test for bitmap overflow in ebitmap_set_bit. + +1.12.3 2006-03-27 + * Fixed attr_convert_callback and expand_convert_type_set + typemap bug. + +1.12.2 2006-03-24 + * Fixed avrule_block_write num_decls endian bug. + +1.12.1 2006-03-20 + * Fixed sepol_module_package_write buffer overflow bug. + +1.12 2006-03-14 + * Updated version for release. + +1.11.20 2006-03-08 + * Merged cond_evaluate_expr fix from Serge Hallyn (IBM). + * Fixed bug in copy_avrule_list reported by Ivan Gyurdiev. + +1.11.19 2006-02-21 + * Merged sepol_policydb_mls_enabled interface and error handling + changes from Ivan Gyurdiev. + +1.11.18 2006-02-16 + * Merged node_expand_addr bugfix and node_compare* change from + Ivan Gyurdiev. + +1.11.17 2006-02-15 + * Merged nodes, ports: always prepend patch from Ivan Gyurdiev. + * Merged bug fix patch from Ivan Gyurdiev. + +1.11.16 2006-02-14 + * Added a defined flag to level_datum_t for use by checkpolicy. + +1.11.15 2006-02-14 + * Merged nodecon support patch from Ivan Gyurdiev. + * Merged cleanups patch from Ivan Gyurdiev. + +1.11.14 2006-02-13 + * Merged optionals in base patch from Joshua Brindle. + +1.11.13 2006-02-07 + * Merged seuser/user_extra support patch from Joshua Brindle. + * Merged fix patch from Ivan Gyurdiev. + +1.11.12 2006-02-02 + * Merged clone record on set_con patch from Ivan Gyurdiev. + +1.11.11 2006-02-01 + * Merged assertion copying bugfix from Joshua Brindle. + * Merged sepol_av_to_string patch from Joshua Brindle. + +1.11.10 2006-01-30 + * Merged cond_expr mapping and package section count bug fixes + from Joshua Brindle. + * Merged improve port/fcontext API patch from Ivan Gyurdiev. + * Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev. + +1.11.9 2006-01-12 + * Merged size_t -> unsigned int patch from Ivan Gyurdiev. + +1.11.8 2006-01-09 + * Merged 2nd const in APIs patch from Ivan Gyurdiev. + +1.11.7 2006-01-06 + * Merged const in APIs patch from Ivan Gyurdiev. + * Merged compare2 function patch from Ivan Gyurdiev. + +1.11.6 2006-01-06 + * Fixed hierarchy checker to only check allow rules. + +1.11.5 2006-01-05 + * Merged further fixes from Russell Coker, specifically: + - av_to_string overflow checking + - sepol_context_to_string error handling + - hierarchy checking memory leak fixes and optimizations + - avrule_block_read variable initialization + * Marked deprecated code in genbools and genusers. + +1.11.4 2006-01-05 + * Merged bugfix for sepol_port_modify from Russell Coker. + +1.11.3 2006-01-05 + * Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev. + * Merged port ordering patch from Ivan Gyurdiev. + +1.11.2 2006-01-04 + * Merged patch series from Ivan Gyurdiev. + This includes patches to: + - support ordering of records in compare function + - enable port interfaces + - add interfaces for context validity and range checks + - add include guards + +1.11.1 2005-12-16 + * Fixed mls_range_cpy bug. + +1.10 2005-12-07 + * Updated version for release. + +1.9.42 2005-12-05 + * Dropped handle from user_del_role interface. + +1.9.41 2005-11-28 + * Merged remove defrole from sepol patch from Ivan Gyurdiev. + +1.9.40 2005-11-15 + * Merged module function and map file cleanup from Ivan Gyurdiev. + * Merged MLS and genusers cleanups from Ivan Gyurdiev. + +1.9.39 2005-11-09 + Prepare for removal of booleans* and *.users files. + * Cleaned up sepol_genbools to not regenerate the image if + there were no changes in the boolean values, including the + degenerate case where there are no booleans or booleans.local + files. + * Cleaned up sepol_genusers to not warn on missing local.users. + +1.9.38 2005-11-08 + * Removed sepol_port_* from libsepol.map, as the port interfaces + are not yet stable. + +1.9.37 2005-11-04 + * Merged context destroy cleanup patch from Ivan Gyurdiev. + +1.9.36 2005-11-03 + * Merged context_to_string interface change patch from Ivan Gyurdiev. + +1.9.35 2005-11-01 + * Added src/dso.h and src/*_internal.h. + Added hidden_def for exported symbols used within libsepol. + Added hidden for symbols that should not be exported by + the wildcards in libsepol.map. + +1.9.34 2005-10-31 + * Merged record interface, record bugfix, and set_roles patches + from Ivan Gyurdiev. + +1.9.33 2005-10-27 + * Merged count specification change from Ivan Gyurdiev. + +1.9.32 2005-10-26 + * Added further checking and error reporting to + sepol_module_package_read and _info. + +1.9.31 2005-10-26 + * Merged sepol handle passing, DEBUG conversion, and memory leak + fix patches from Ivan Gyurdiev. + +1.9.30 2005-10-25 + * Removed processing of system.users from sepol_genusers and + dropped delusers logic. + +1.9.29 2005-10-25 + * Removed policydb_destroy from error path of policydb_read, + since create/init/destroy/free of policydb is handled by the + caller now. + * Fixed sepol_module_package_read to handle a failed policydb_read + properly. + +1.9.28 2005-10-25 + * Merged query/exists and count patches from Ivan Gyurdiev. + +1.9.27 2005-10-25 + * Merged fix for pruned types in expand code from Joshua Brindle. + * Merged new module package format code from Joshua Brindle. + +1.9.26 2005-10-24 + * Merged context interface cleanup, record conversion code, + key passing, and bug fix patches from Ivan Gyurdiev. + +1.9.25 2005-10-21 + * Merged users cleanup patch from Ivan Gyurdiev. + +1.9.24 2005-10-21 + * Merged user record memory leak fix from Ivan Gyurdiev. + * Merged reorganize users patch from Ivan Gyurdiev. + +1.9.23 2005-10-19 + * Added check flag to expand_module() to control assertion + and hierarchy checking on expansion. + +1.9.22 2005-10-19 + * Reworked check_assertions() and hierarchy_check_constraints() + to take handles and use callback-based error reporting. + * Changed expand_module() to call check_assertions() and + hierarchy_check_constraints() prior to returning the expanded + policy. + +1.9.21 2005-10-18 + * Changed sepol_module_package_set_file_contexts to copy the + file contexts data since it is internally managed. + +1.9.20 2005-10-18 + * Added sepol_policy_file_set_handle interface to associate + a handle with a policy file. + * Added handle argument to policydb_from_image/to_image. + * Added sepol_module_package_set_file_contexts interface. + * Dropped sepol_module_package_create_file interface. + * Reworked policydb_read/write, policydb_from_image/to_image, + and sepol_module_package_read/write to use callback-based error + reporting system rather than DEBUG. + +1.9.19 2005-10-17 + * Reworked link_packages, link_modules, and expand_module to use + callback-based error reporting system rather than error buffering. + +1.9.18 2005-10-14 + * Merged conditional expression mapping fix in the module linking + code from Joshua Brindle. + +1.9.17 2005-10-13 + * Hid sepol_module_package type definition, and added get interfaces. + +1.9.16 2005-10-13 + * Merged new callback-based error reporting system from Ivan + Gyurdiev. + +1.9.15 2005-10-13 + * Merged support for require blocks inside conditionals from + Joshua Brindle (Tresys). + +1.9.14 2005-10-07 + * Fixed use of policydb_from_image/to_image to ensure proper + init of policydb. + +1.9.13 2005-10-07 + * Isolated policydb internal headers under <sepol/policydb/*.h>. + These headers should only be used by users of the static libsepol. + Created new <sepol/policydb.h> with new public types and interfaces + for shared libsepol. + Created new <sepol/module.h> with public types and interfaces moved + or wrapped from old module.h, link.h, and expand.h, adjusted for + new public types for policydb and policy_file. + Added public interfaces to libsepol.map. + Some implementation changes visible to users of the static libsepol: + 1) policydb_read no longer calls policydb_init. + Caller must do so first. + 2) policydb_init no longer takes policy_type argument. + Caller must set policy_type separately. + 3) expand_module automatically enables the global branch. + Caller no longer needs to do so. + 4) policydb_write uses the policy_type and policyvers from the + policydb itself, and sepol_set_policyvers() has been removed. + +1.9.12 2005-10-06 + * Merged function renaming and static cleanup from Ivan Gyurdiev. + +1.9.11 2005-10-05 + * Merged bug fix for check_assertions handling of no assertions + from Joshua Brindle (Tresys). + +1.9.10 2005-10-04 + * Merged iterate patch from Ivan Gyurdiev. + +1.9.9 2005-10-03 + * Merged MLS in modules patch from Joshua Brindle (Tresys). + +1.9.8 2005-09-30 + * Merged pointer typedef elimination patch from Ivan Gyurdiev. + * Merged user list function, new mls functions, and bugfix patch + from Ivan Gyurdiev. + +1.9.7 2005-09-28 + * Merged sepol_get_num_roles fix from Karl MacMillan (Tresys). + +1.9.6 2005-09-23 + * Merged bug fix patches from Joshua Brindle (Tresys). + +1.9.5 2005-09-21 + * Merged boolean record and memory leak fix patches from Ivan + Gyurdiev. + +1.9.4 2005-09-19 + * Merged interface record patch from Ivan Gyurdiev. + +1.9.3 2005-09-14 + * Merged fix for sepol_enable/disable_debug from Ivan + Gyurdiev. + +1.9.2 2005-09-14 + * Merged stddef.h patch and debug conversion patch from + Ivan Gyurdiev. + +1.9.1 2005-09-09 + * Fixed expand_avtab and expand_cond_av_list to keep separate + entries with identical keys but different enabled flags. + +1.8 2005-09-06 + * Updated version for release. + +1.7.24 2005-08-31 + * Fixed symtab_insert return value for duplicate declarations. + +1.7.23 2005-08-31 + * Merged fix for memory error in policy_module_destroy from + Jason Tang (Tresys). + +1.7.22 2005-08-26 + * Merged fix for memory leak in sepol_context_to_sid from + Jason Tang (Tresys). + +1.7.21 2005-08-25 + * Merged fixes for resource leaks on error paths and + change to scope_destroy from Joshua Brindle (Tresys). + +1.7.20 2005-08-23 + * Merged more fixes for resource leaks on error paths + from Serge Hallyn (IBM). Bugs found by Coverity. + +1.7.19 2005-08-19 + * Changed to treat all type conflicts as fatal errors. + +1.7.18 2005-08-18 + * Merged several error handling fixes from + Serge Hallyn (IBM). Bugs found by Coverity. + +1.7.17 2005-08-15 + * Fixed further memory leaks found by valgrind. + +1.7.16 2005-08-15 + * Fixed several memory leaks found by valgrind. + +1.7.15 2005-08-12 + * Fixed empty list test in cond_write_av_list. Bug found by + Coverity, reported by Serge Hallyn (IBM). + * Merged patch to policydb_write to check errors + when writing the type->attribute reverse map from + Serge Hallyn (IBM). Bug found by Coverity. + * Fixed policydb_destroy to properly handle NULL type_attr_map + or attr_type_map. + +1.7.14 2005-08-12 + * Fixed use of uninitialized data by expand_avtab_node by + clearing type_val_to_struct in policydb_index_others. + +1.7.13 2005-08-11 + * Improved memory use by SELinux by both reducing the avtab + node size and reducing the number of avtab nodes (by not + expanding attributes in TE rules when possible). Added + expand_avtab and expand_cond_av_list functions for use by + assertion checker, hierarchy checker, compatibility code, + and dispol. Added new inline ebitmap operators and converted + existing users of ebitmaps to the new operators for greater + efficiency. + Note: The binary policy format version has been incremented to + version 20 as a result of these changes. + +1.7.12 2005-08-10 + * Fixed bug in constraint_node_clone handling of name sets. + +1.7.11 2005-08-08 + * Fix range_trans_clone to map the type values properly. + +1.7.10 2005-08-02 + * Merged patch to move module read/write code from libsemanage + to libsepol from Jason Tang (Tresys). + +1.7.9 2005-08-02 + * Enabled further compiler warning flags and fixed them. + +1.7.8 2005-08-02 + * Merged user, context, port records patch from Ivan Gyurdiev. + * Merged key extract function patch from Ivan Gyurdiev. + +1.7.7 2005-07-27 + * Merged mls_context_to_sid bugfix from Ivan Gyurdiev. + +1.7.6 2005-07-26 + * Merged context reorganization, memory leak fixes, + port and interface loading, replacements for genusers and + genbools, debug traceback, and bugfix patches from Ivan Gyurdiev. + * Merged uninitialized variable bugfix from Dan Walsh. + +1.7.5 2005-07-18 + * Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat). + * Removed genpolbools and genpolusers utilities. + +1.7.4 2005-07-18 + * Merged hierarchy check fix from Joshua Brindle (Tresys). + +1.7.3 2005-07-13 + * Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat). + +1.7.2 2005-07-11 + * Merged genbools debugging message cleanup from Red Hat. + +1.7.1 2005-07-06 + * Merged loadable module support from Tresys Technology. + +1.6 2005-06-20 + * Updated version for release. + +1.5.10 2005-05-19 + * License changed to LGPL v2.1, see COPYING. + +1.5.9 2005-05-16 + * Added sepol_genbools_policydb and sepol_genusers_policydb for + audit2why. + +1.5.8 2005-05-13 + * Added sepol_ prefix to Flask types to avoid + namespace collision with libselinux. + +1.5.7 2005-05-13 + * Added sepol_compute_av_reason() for audit2why. + +1.5.6 2005-04-25 + * Fixed bug in role hierarchy checker. + +1.5.5 2005-04-13 + * Merged hierarchical type/role patch from Tresys Technology. + * Merged MLS fixes from Darrel Goeddel of TCS. + +1.5.4 2005-04-13 + * Changed sepol_genusers to not delete users by default, + and added a sepol_set_delusers function to enable deletion. + Also, removed special case handling of system_u and user_u. + +1.5.3 2005-03-29 + * Merged booleans.local patch from Dan Walsh. + +1.5.2 2005-03-16 + * Added man page for sepol_check_context. + +1.5.1 2005-03-15 + * Added man page for sepol_genusers function. + * Merged man pages for genpolusers and chkcon from Manoj Srivastava. + +1.4 2005-03-09 + * Updated version for release. + +1.3.8 2005-03-08 + * Cleaned up error handling in sepol_genusers and sepol_genbools. + +1.3.7 2005-02-28 + * Merged sepol_debug and fclose patch from Dan Walsh. + +1.3.6 2005-02-22 + * Changed sepol_genusers to also use getline and correctly handle + EOL. + +1.3.5 2005-02-17 + * Merged range_transition support from Darrel Goeddel (TCS). + +1.3.4 2005-02-16 + * Added sepol_genusers function. + +1.3.3 2005-02-14 + * Merged endianness and compute_av patches from Darrel Goeddel (TCS). + +1.3.2 2005-02-09 + * Changed relabel Makefile target to use restorecon. + +1.3.1 2005-01-26 + * Merged enhanced MLS support from Darrel Goeddel (TCS). + +1.2.1 2005-01-19 + * Merged build fix patch from Manoj Srivastava. + +1.2 2004-10-07 + * MLS build fixes. + * Added sepol_set_policydb_from_file and sepol_check_context for setfiles. + +1.0 2004-08-19 + * Initial public release. + +0.4 2004-08-13 + * Merged patch from Dan Walsh to ignore case on booleans. + * Changed sepol_genbools* to preserve the original policy version. + * Replaced exported global variables with set functions. + * Moved genpolbools utility from checkpolicy to libsepol. + * Added man pages for sepol_genbools* and genpolbools. + +0.3 2004-08-10 + * Added ChangeLog, COPYING, spec file. + * Added sepol_genbools_array() for load_policy. + * Created libsepol.map to limit exported symbols in shared library. + +0.2 2004-08-09 + * Exported other functions for checkpolicy and friends. + * Renamed service and sidtab functions to avoid libselinux conflict. + * Removed original code from checkpolicy, which now uses libsepol. + * Code cleanup: kill legacy references to kernel types/functions. + +0.1 2004-08-06 + * Moved checkpolicy core logic into a library. + * Exported sepol_genbools() for load_policy.
diff --git a/selinux/libsepol/Makefile b/selinux/libsepol/Makefile new file mode 100644 index 0000000..5b5d03e --- /dev/null +++ b/selinux/libsepol/Makefile
@@ -0,0 +1,30 @@ +DISABLE_CIL ?= n + +export DISABLE_CIL + +all: + $(MAKE) -C src + $(MAKE) -C utils + +install: + $(MAKE) -C include install + $(MAKE) -C src install + $(MAKE) -C utils install + $(MAKE) -C man install + +relabel: + $(MAKE) -C src relabel + +clean: + $(MAKE) -C src clean + $(MAKE) -C utils clean + $(MAKE) -C tests clean + +indent: + $(MAKE) -C src $@ + $(MAKE) -C include $@ + $(MAKE) -C utils $@ + +test: + $(MAKE) -C tests test +
diff --git a/selinux/libsepol/VERSION b/selinux/libsepol/VERSION new file mode 100644 index 0000000..95e3ba8 --- /dev/null +++ b/selinux/libsepol/VERSION
@@ -0,0 +1 @@ +2.5
diff --git a/selinux/libsepol/cil/include/cil/cil.h b/selinux/libsepol/cil/include/cil/cil.h new file mode 100644 index 0000000..e4b10c5 --- /dev/null +++ b/selinux/libsepol/cil/include/cil/cil.h
@@ -0,0 +1,71 @@ +/* + * Copyright 2011 Tresys Technology, LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those + * of the authors and should not be interpreted as representing official policies, + * either expressed or implied, of Tresys Technology, LLC. + */ + +#ifndef CIL_H_ +#define CIL_H_ + +#include <sepol/policydb/policydb.h> + +struct cil_db; +typedef struct cil_db cil_db_t; + +extern void cil_db_init(cil_db_t **db); +extern void cil_db_destroy(cil_db_t **db); + +extern int cil_add_file(cil_db_t *db, char *name, char *data, size_t size); + +extern int cil_compile(cil_db_t *db); +extern int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db); +extern int cil_userprefixes_to_string(cil_db_t *db, char **out, size_t *size); +extern int cil_selinuxusers_to_string(cil_db_t *db, char **out, size_t *size); +extern int cil_filecons_to_string(cil_db_t *db, char **out, size_t *size); +extern void cil_set_disable_dontaudit(cil_db_t *db, int disable_dontaudit); +extern void cil_set_disable_neverallow(cil_db_t *db, int disable_neverallow); +extern void cil_set_preserve_tunables(cil_db_t *db, int preserve_tunables); +extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown); +extern void cil_set_mls(cil_db_t *db, int mls); +extern void cil_set_target_platform(cil_db_t *db, int target_platform); +extern void cil_set_policy_version(cil_db_t *db, int policy_version); + +enum cil_log_level { + CIL_ERR = 1, + CIL_WARN, + CIL_INFO +}; +extern void cil_set_log_level(enum cil_log_level lvl); +extern void cil_set_log_handler(void (*handler)(int lvl, char *msg)); + +#ifdef __GNUC__ +__attribute__ ((format(printf, 2, 3))) +#endif +extern void cil_log(enum cil_log_level lvl, const char *msg, ...); + +extern void cil_set_malloc_error_handler(void (*handler)(void)); + +#endif
diff --git a/selinux/libsepol/cil/src/cil.c b/selinux/libsepol/cil/src/cil.c new file mode 100644 index 0000000..929ab19 --- /dev/null +++ b/selinux/libsepol/cil/src/cil.c
@@ -0,0 +1,2570 @@ +/* + * Copyright 2011 Tresys Technology, LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those + * of the authors and should not be interpreted as representing official policies, + * either expressed or implied, of Tresys Technology, LLC. + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/symtab.h> + +#include "cil_internal.h" +#include "cil_flavor.h" +#include "cil_log.h" +#include "cil_mem.h" +#include "cil_tree.h" +#include "cil_list.h" +#include "cil_symtab.h" +#include "cil_build_ast.h" + +#include "cil_parser.h" +#include "cil_build_ast.h" +#include "cil_resolve_ast.h" +#include "cil_fqn.h" +#include "cil_post.h" +#include "cil_binary.h" +#include "cil_policy.h" +#include "cil_strpool.h" +#include "dso.h" + +#ifndef DISABLE_SYMVER +asm(".symver cil_build_policydb_pdb, cil_build_policydb@"); +asm(".symver cil_build_policydb_create_pdb, cil_build_policydb@@LIBSEPOL_1.1"); + +asm(".symver cil_compile_pdb, cil_compile@"); +asm(".symver cil_compile_nopdb, cil_compile@@LIBSEPOL_1.1"); + +asm(".symver cil_userprefixes_to_string_pdb, cil_userprefixes_to_string@"); +asm(".symver cil_userprefixes_to_string_nopdb, cil_userprefixes_to_string@@LIBSEPOL_1.1"); + +asm(".symver cil_selinuxusers_to_string_pdb, cil_selinuxusers_to_string@"); +asm(".symver cil_selinuxusers_to_string_nopdb, cil_selinuxusers_to_string@@LIBSEPOL_1.1"); + +asm(".symver cil_filecons_to_string_pdb, cil_filecons_to_string@"); +asm(".symver cil_filecons_to_string_nopdb, cil_filecons_to_string@@LIBSEPOL_1.1"); +#endif + +int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = { + {64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, + {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} +}; + +static void cil_init_keys(void) +{ + /* Initialize CIL Keys into strpool */ + CIL_KEY_CONS_T1 = cil_strpool_add("t1"); + CIL_KEY_CONS_T2 = cil_strpool_add("t2"); + CIL_KEY_CONS_T3 = cil_strpool_add("t3"); + CIL_KEY_CONS_R1 = cil_strpool_add("r1"); + CIL_KEY_CONS_R2 = cil_strpool_add("r2"); + CIL_KEY_CONS_R3 = cil_strpool_add("r3"); + CIL_KEY_CONS_U1 = cil_strpool_add("u1"); + CIL_KEY_CONS_U2 = cil_strpool_add("u2"); + CIL_KEY_CONS_U3 = cil_strpool_add("u3"); + CIL_KEY_CONS_L1 = cil_strpool_add("l1"); + CIL_KEY_CONS_L2 = cil_strpool_add("l2"); + CIL_KEY_CONS_H1 = cil_strpool_add("h1"); + CIL_KEY_CONS_H2 = cil_strpool_add("h2"); + CIL_KEY_AND = cil_strpool_add("and"); + CIL_KEY_OR = cil_strpool_add("or"); + CIL_KEY_NOT = cil_strpool_add("not"); + CIL_KEY_EQ = cil_strpool_add("eq"); + CIL_KEY_NEQ = cil_strpool_add("neq"); + CIL_KEY_CONS_DOM = cil_strpool_add("dom"); + CIL_KEY_CONS_DOMBY = cil_strpool_add("domby"); + CIL_KEY_CONS_INCOMP = cil_strpool_add("incomp"); + CIL_KEY_CONDTRUE = cil_strpool_add("true"); + CIL_KEY_CONDFALSE = cil_strpool_add("false"); + CIL_KEY_SELF = cil_strpool_add("self"); + CIL_KEY_OBJECT_R = cil_strpool_add("object_r"); + CIL_KEY_STAR = cil_strpool_add("*"); + CIL_KEY_UDP = cil_strpool_add("udp"); + CIL_KEY_TCP = cil_strpool_add("tcp"); + CIL_KEY_DCCP = cil_strpool_add("dccp"); + CIL_KEY_AUDITALLOW = cil_strpool_add("auditallow"); + CIL_KEY_TUNABLEIF = cil_strpool_add("tunableif"); + CIL_KEY_ALLOW = cil_strpool_add("allow"); + CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit"); + CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition"); + CIL_KEY_TYPECHANGE = cil_strpool_add("typechange"); + CIL_KEY_CALL = cil_strpool_add("call"); + CIL_KEY_TUNABLE = cil_strpool_add("tunable"); + CIL_KEY_XOR = cil_strpool_add("xor"); + CIL_KEY_ALL = cil_strpool_add("all"); + CIL_KEY_RANGE = cil_strpool_add("range"); + CIL_KEY_TYPE = cil_strpool_add("type"); + CIL_KEY_ROLE = cil_strpool_add("role"); + CIL_KEY_USER = cil_strpool_add("user"); + CIL_KEY_USERATTRIBUTE = cil_strpool_add("userattribute"); + CIL_KEY_USERATTRIBUTESET = cil_strpool_add("userattributeset"); + CIL_KEY_SENSITIVITY = cil_strpool_add("sensitivity"); + CIL_KEY_CATEGORY = cil_strpool_add("category"); + CIL_KEY_CATSET = cil_strpool_add("categoryset"); + CIL_KEY_LEVEL = cil_strpool_add("level"); + CIL_KEY_LEVELRANGE = cil_strpool_add("levelrange"); + CIL_KEY_CLASS = cil_strpool_add("class"); + CIL_KEY_IPADDR = cil_strpool_add("ipaddr"); + CIL_KEY_MAP_CLASS = cil_strpool_add("classmap"); + CIL_KEY_CLASSPERMISSION = cil_strpool_add("classpermission"); + CIL_KEY_BOOL = cil_strpool_add("boolean"); + CIL_KEY_STRING = cil_strpool_add("string"); + CIL_KEY_NAME = cil_strpool_add("name"); + CIL_KEY_HANDLEUNKNOWN = cil_strpool_add("handleunknown"); + CIL_KEY_HANDLEUNKNOWN_ALLOW = cil_strpool_add("allow"); + CIL_KEY_HANDLEUNKNOWN_DENY = cil_strpool_add("deny"); + CIL_KEY_HANDLEUNKNOWN_REJECT = cil_strpool_add("reject"); + CIL_KEY_BLOCKINHERIT = cil_strpool_add("blockinherit"); + CIL_KEY_BLOCKABSTRACT = cil_strpool_add("blockabstract"); + CIL_KEY_CLASSORDER = cil_strpool_add("classorder"); + CIL_KEY_CLASSMAPPING = cil_strpool_add("classmapping"); + CIL_KEY_CLASSPERMISSIONSET = cil_strpool_add("classpermissionset"); + CIL_KEY_COMMON = cil_strpool_add("common"); + CIL_KEY_CLASSCOMMON = cil_strpool_add("classcommon"); + CIL_KEY_SID = cil_strpool_add("sid"); + CIL_KEY_SIDCONTEXT = cil_strpool_add("sidcontext"); + CIL_KEY_SIDORDER = cil_strpool_add("sidorder"); + CIL_KEY_USERLEVEL = cil_strpool_add("userlevel"); + CIL_KEY_USERRANGE = cil_strpool_add("userrange"); + CIL_KEY_USERBOUNDS = cil_strpool_add("userbounds"); + CIL_KEY_USERPREFIX = cil_strpool_add("userprefix"); + CIL_KEY_SELINUXUSER = cil_strpool_add("selinuxuser"); + CIL_KEY_SELINUXUSERDEFAULT = cil_strpool_add("selinuxuserdefault"); + CIL_KEY_TYPEATTRIBUTE = cil_strpool_add("typeattribute"); + CIL_KEY_TYPEATTRIBUTESET = cil_strpool_add("typeattributeset"); + CIL_KEY_TYPEALIAS = cil_strpool_add("typealias"); + CIL_KEY_TYPEALIASACTUAL = cil_strpool_add("typealiasactual"); + CIL_KEY_TYPEBOUNDS = cil_strpool_add("typebounds"); + CIL_KEY_TYPEPERMISSIVE = cil_strpool_add("typepermissive"); + CIL_KEY_RANGETRANSITION = cil_strpool_add("rangetransition"); + CIL_KEY_USERROLE = cil_strpool_add("userrole"); + CIL_KEY_ROLETYPE = cil_strpool_add("roletype"); + CIL_KEY_ROLETRANSITION = cil_strpool_add("roletransition"); + CIL_KEY_ROLEALLOW = cil_strpool_add("roleallow"); + CIL_KEY_ROLEATTRIBUTE = cil_strpool_add("roleattribute"); + CIL_KEY_ROLEATTRIBUTESET = cil_strpool_add("roleattributeset"); + CIL_KEY_ROLEBOUNDS = cil_strpool_add("rolebounds"); + CIL_KEY_BOOLEANIF = cil_strpool_add("booleanif"); + CIL_KEY_NEVERALLOW = cil_strpool_add("neverallow"); + CIL_KEY_TYPEMEMBER = cil_strpool_add("typemember"); + CIL_KEY_SENSALIAS = cil_strpool_add("sensitivityalias"); + CIL_KEY_SENSALIASACTUAL = cil_strpool_add("sensitivityaliasactual"); + CIL_KEY_CATALIAS = cil_strpool_add("categoryalias"); + CIL_KEY_CATALIASACTUAL = cil_strpool_add("categoryaliasactual"); + CIL_KEY_CATORDER = cil_strpool_add("categoryorder"); + CIL_KEY_SENSITIVITYORDER = cil_strpool_add("sensitivityorder"); + CIL_KEY_SENSCAT = cil_strpool_add("sensitivitycategory"); + CIL_KEY_CONSTRAIN = cil_strpool_add("constrain"); + CIL_KEY_MLSCONSTRAIN = cil_strpool_add("mlsconstrain"); + CIL_KEY_VALIDATETRANS = cil_strpool_add("validatetrans"); + CIL_KEY_MLSVALIDATETRANS = cil_strpool_add("mlsvalidatetrans"); + CIL_KEY_CONTEXT = cil_strpool_add("context"); + CIL_KEY_FILECON = cil_strpool_add("filecon"); + CIL_KEY_PORTCON = cil_strpool_add("portcon"); + CIL_KEY_NODECON = cil_strpool_add("nodecon"); + CIL_KEY_GENFSCON = cil_strpool_add("genfscon"); + CIL_KEY_NETIFCON = cil_strpool_add("netifcon"); + CIL_KEY_PIRQCON = cil_strpool_add("pirqcon"); + CIL_KEY_IOMEMCON = cil_strpool_add("iomemcon"); + CIL_KEY_IOPORTCON = cil_strpool_add("ioportcon"); + CIL_KEY_PCIDEVICECON = cil_strpool_add("pcidevicecon"); + CIL_KEY_DEVICETREECON = cil_strpool_add("devicetreecon"); + CIL_KEY_FSUSE = cil_strpool_add("fsuse"); + CIL_KEY_POLICYCAP = cil_strpool_add("policycap"); + CIL_KEY_OPTIONAL = cil_strpool_add("optional"); + CIL_KEY_DEFAULTUSER = cil_strpool_add("defaultuser"); + CIL_KEY_DEFAULTROLE = cil_strpool_add("defaultrole"); + CIL_KEY_DEFAULTTYPE = cil_strpool_add("defaulttype"); + CIL_KEY_MACRO = cil_strpool_add("macro"); + CIL_KEY_IN = cil_strpool_add("in"); + CIL_KEY_MLS = cil_strpool_add("mls"); + CIL_KEY_DEFAULTRANGE = cil_strpool_add("defaultrange"); + CIL_KEY_GLOB = cil_strpool_add("*"); + CIL_KEY_FILE = cil_strpool_add("file"); + CIL_KEY_DIR = cil_strpool_add("dir"); + CIL_KEY_CHAR = cil_strpool_add("char"); + CIL_KEY_BLOCK = cil_strpool_add("block"); + CIL_KEY_SOCKET = cil_strpool_add("socket"); + CIL_KEY_PIPE = cil_strpool_add("pipe"); + CIL_KEY_SYMLINK = cil_strpool_add("symlink"); + CIL_KEY_ANY = cil_strpool_add("any"); + CIL_KEY_XATTR = cil_strpool_add("xattr"); + CIL_KEY_TASK = cil_strpool_add("task"); + CIL_KEY_TRANS = cil_strpool_add("trans"); + CIL_KEY_SOURCE = cil_strpool_add("source"); + CIL_KEY_TARGET = cil_strpool_add("target"); + CIL_KEY_LOW = cil_strpool_add("low"); + CIL_KEY_HIGH = cil_strpool_add("high"); + CIL_KEY_LOW_HIGH = cil_strpool_add("low-high"); + CIL_KEY_ROOT = cil_strpool_add("<root>"); + CIL_KEY_NODE = cil_strpool_add("<node>"); + CIL_KEY_PERM = cil_strpool_add("perm"); + CIL_KEY_ALLOWX = cil_strpool_add("allowx"); + CIL_KEY_AUDITALLOWX = cil_strpool_add("auditallowx"); + CIL_KEY_DONTAUDITX = cil_strpool_add("dontauditx"); + CIL_KEY_NEVERALLOWX = cil_strpool_add("neverallowx"); + CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx"); + CIL_KEY_IOCTL = cil_strpool_add("ioctl"); + CIL_KEY_UNORDERED = cil_strpool_add("unordered"); + CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>"); + CIL_KEY_SRC_CIL = cil_strpool_add("<src_cil>"); + CIL_KEY_SRC_HLL = cil_strpool_add("<src_hll>"); +} + +void cil_db_init(struct cil_db **db) +{ + *db = cil_malloc(sizeof(**db)); + + cil_strpool_init(); + cil_init_keys(); + + cil_tree_init(&(*db)->parse); + cil_tree_init(&(*db)->ast); + cil_root_init((struct cil_root **)&(*db)->ast->root->data); + (*db)->sidorder = NULL; + (*db)->classorder = NULL; + (*db)->catorder = NULL; + (*db)->sensitivityorder = NULL; + cil_sort_init(&(*db)->netifcon); + cil_sort_init(&(*db)->genfscon); + cil_sort_init(&(*db)->filecon); + cil_sort_init(&(*db)->nodecon); + cil_sort_init(&(*db)->portcon); + cil_sort_init(&(*db)->pirqcon); + cil_sort_init(&(*db)->iomemcon); + cil_sort_init(&(*db)->ioportcon); + cil_sort_init(&(*db)->pcidevicecon); + cil_sort_init(&(*db)->devicetreecon); + cil_sort_init(&(*db)->fsuse); + cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM); + cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM); + cil_list_init(&(*db)->names, CIL_LIST_ITEM); + + cil_type_init(&(*db)->selftype); + (*db)->selftype->datum.name = CIL_KEY_SELF; + (*db)->selftype->datum.fqn = CIL_KEY_SELF; + (*db)->num_types_and_attrs = 0; + (*db)->num_classes = 0; + (*db)->num_types = 0; + (*db)->num_roles = 0; + (*db)->num_users = 0; + (*db)->num_cats = 0; + (*db)->val_to_type = NULL; + (*db)->val_to_role = NULL; + (*db)->val_to_user = NULL; + + (*db)->disable_dontaudit = CIL_FALSE; + (*db)->disable_neverallow = CIL_FALSE; + (*db)->preserve_tunables = CIL_FALSE; + (*db)->handle_unknown = -1; + (*db)->mls = -1; + (*db)->target_platform = SEPOL_TARGET_SELINUX; + (*db)->policy_version = POLICYDB_VERSION_MAX; +} + +void cil_db_destroy(struct cil_db **db) +{ + if (db == NULL || *db == NULL) { + return; + } + + cil_tree_destroy(&(*db)->parse); + cil_tree_destroy(&(*db)->ast); + cil_list_destroy(&(*db)->sidorder, CIL_FALSE); + cil_list_destroy(&(*db)->classorder, CIL_FALSE); + cil_list_destroy(&(*db)->catorder, CIL_FALSE); + cil_list_destroy(&(*db)->sensitivityorder, CIL_FALSE); + cil_sort_destroy(&(*db)->netifcon); + cil_sort_destroy(&(*db)->genfscon); + cil_sort_destroy(&(*db)->filecon); + cil_sort_destroy(&(*db)->nodecon); + cil_sort_destroy(&(*db)->portcon); + cil_sort_destroy(&(*db)->pirqcon); + cil_sort_destroy(&(*db)->iomemcon); + cil_sort_destroy(&(*db)->ioportcon); + cil_sort_destroy(&(*db)->pcidevicecon); + cil_sort_destroy(&(*db)->devicetreecon); + cil_sort_destroy(&(*db)->fsuse); + cil_list_destroy(&(*db)->userprefixes, CIL_FALSE); + cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE); + cil_list_destroy(&(*db)->names, CIL_TRUE); + + cil_destroy_type((*db)->selftype); + + cil_strpool_destroy(); + free((*db)->val_to_type); + free((*db)->val_to_role); + free((*db)->val_to_user); + + free(*db); + *db = NULL; +} + +void cil_root_init(struct cil_root **root) +{ + struct cil_root *r = cil_malloc(sizeof(*r)); + cil_symtab_array_init(r->symtab, cil_sym_sizes[CIL_SYM_ARRAY_ROOT]); + + *root = r; +} + +void cil_root_destroy(struct cil_root *root) +{ + if (root == NULL) { + return; + } + cil_symtab_array_destroy(root->symtab); + free(root); +} + +int cil_add_file(cil_db_t *db, char *name, char *data, size_t size) +{ + char *buffer = NULL; + int rc; + + cil_log(CIL_INFO, "Parsing %s\n", name); + + buffer = cil_malloc(size + 2); + memcpy(buffer, data, size); + memset(buffer + size, 0, 2); + + rc = cil_parser(name, buffer, size + 2, &db->parse); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to parse %s\n", name); + goto exit; + } + + free(buffer); + buffer = NULL; + + rc = SEPOL_OK; + +exit: + free(buffer); + + return rc; +} + +#ifdef DISABLE_SYMVER +int cil_compile(struct cil_db *db) +#else +int cil_compile_nopdb(struct cil_db *db) +#endif +{ + int rc = SEPOL_ERR; + + if (db == NULL) { + goto exit; + } + + cil_log(CIL_INFO, "Building AST from Parse Tree\n"); + rc = cil_build_ast(db, db->parse->root, db->ast->root); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to build ast\n"); + goto exit; + } + + cil_log(CIL_INFO, "Destroying Parse Tree\n"); + cil_tree_destroy(&db->parse); + + cil_log(CIL_INFO, "Resolving AST\n"); + rc = cil_resolve_ast(db, db->ast->root); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to resolve ast\n"); + goto exit; + } + + cil_log(CIL_INFO, "Qualifying Names\n"); + rc = cil_fqn_qualify(db->ast->root); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to qualify names\n"); + goto exit; + } + + cil_log(CIL_INFO, "Compile post process\n"); + rc = cil_post_process(db); + if (rc != SEPOL_OK ) { + cil_log(CIL_INFO, "Post process failed\n"); + goto exit; + } + +exit: + + return rc; +} + +#ifndef DISABLE_SYMVER +int cil_compile_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db) +{ + return cil_compile_nopdb(db); +} + +int cil_build_policydb_pdb(cil_db_t *db, sepol_policydb_t *sepol_db) +{ + int rc; + + cil_log(CIL_INFO, "Building policy binary\n"); + rc = cil_binary_create_allocated_pdb(db, sepol_db); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to generate binary\n"); + goto exit; + } + +exit: + return rc; +} +#endif + +#ifdef DISABLE_SYMVER +int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db) +#else +int cil_build_policydb_create_pdb(cil_db_t *db, sepol_policydb_t **sepol_db) +#endif +{ + int rc; + + cil_log(CIL_INFO, "Building policy binary\n"); + rc = cil_binary_create(db, sepol_db); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to generate binary\n"); + goto exit; + } + +exit: + return rc; +} + +void cil_destroy_data(void **data, enum cil_flavor flavor) +{ + if (*data == NULL) { + return; + } + + switch(flavor) { + case CIL_NONE: + break; + case CIL_ROOT: + cil_root_destroy(*data); + break; + case CIL_NODE: + break; + case CIL_STRING: + break; + case CIL_DATUM: + break; + case CIL_LIST: + cil_list_destroy(*data, CIL_FALSE); + break; + case CIL_LIST_ITEM: + break; + case CIL_PARAM: + cil_destroy_param(*data); + break; + case CIL_ARGS: + cil_destroy_args(*data); + break; + case CIL_BLOCK: + cil_destroy_block(*data); + break; + case CIL_BLOCKINHERIT: + cil_destroy_blockinherit(*data); + break; + case CIL_BLOCKABSTRACT: + cil_destroy_blockabstract(*data); + break; + case CIL_IN: + cil_destroy_in(*data); + break; + case CIL_MACRO: + cil_destroy_macro(*data); + break; + case CIL_CALL: + cil_destroy_call(*data); + break; + case CIL_OPTIONAL: + cil_destroy_optional(*data); + break; + case CIL_BOOL: + cil_destroy_bool(*data); + break; + case CIL_BOOLEANIF: + cil_destroy_boolif(*data); + break; + case CIL_TUNABLE: + cil_destroy_tunable(*data); + break; + case CIL_TUNABLEIF: + cil_destroy_tunif(*data); + break; + case CIL_CONDBLOCK: + cil_destroy_condblock(*data); + break; + case CIL_CONDTRUE: + break; + case CIL_CONDFALSE: + break; + case CIL_PERM: + case CIL_MAP_PERM: + cil_destroy_perm(*data); + break; + case CIL_COMMON: + case CIL_CLASS: + case CIL_MAP_CLASS: + cil_destroy_class(*data); + break; + case CIL_CLASSORDER: + cil_destroy_classorder(*data); + break; + case CIL_CLASSPERMISSION: + cil_destroy_classpermission(*data); + break; + case CIL_CLASSCOMMON: + cil_destroy_classcommon(*data); + break; + case CIL_CLASSMAPPING: + cil_destroy_classmapping(*data); + break; + case CIL_CLASSPERMS: + cil_destroy_classperms(*data); + break; + case CIL_CLASSPERMS_SET: + cil_destroy_classperms_set(*data); + break; + case CIL_CLASSPERMISSIONSET: + cil_destroy_classpermissionset(*data); + break; + case CIL_USER: + cil_destroy_user(*data); + break; + case CIL_USERATTRIBUTE: + cil_destroy_userattribute(*data); + break; + case CIL_USERATTRIBUTESET: + cil_destroy_userattributeset(*data); + break; + case CIL_USERPREFIX: + cil_destroy_userprefix(*data); + break; + case CIL_USERROLE: + cil_destroy_userrole(*data); + break; + case CIL_USERLEVEL: + cil_destroy_userlevel(*data); + break; + case CIL_USERRANGE: + cil_destroy_userrange(*data); + break; + case CIL_USERBOUNDS: + cil_destroy_bounds(*data); + break; + case CIL_SELINUXUSER: + case CIL_SELINUXUSERDEFAULT: + cil_destroy_selinuxuser(*data); + break; + case CIL_ROLE: + cil_destroy_role(*data); + break; + case CIL_ROLEATTRIBUTE: + cil_destroy_roleattribute(*data); + break; + case CIL_ROLEATTRIBUTESET: + cil_destroy_roleattributeset(*data); + break; + case CIL_ROLETYPE: + cil_destroy_roletype(*data); + break; + case CIL_ROLEBOUNDS: + cil_destroy_bounds(*data); + break; + case CIL_TYPE: + cil_destroy_type(*data); + break; + case CIL_TYPEATTRIBUTE: + cil_destroy_typeattribute(*data); + break; + case CIL_TYPEALIAS: + cil_destroy_alias(*data); + break; + case CIL_TYPEATTRIBUTESET: + cil_destroy_typeattributeset(*data); + break; + case CIL_TYPEALIASACTUAL: + cil_destroy_aliasactual(*data); + break; + case CIL_TYPEBOUNDS: + cil_destroy_bounds(*data); + break; + case CIL_TYPEPERMISSIVE: + cil_destroy_typepermissive(*data); + break; + case CIL_SENS: + cil_destroy_sensitivity(*data); + break; + case CIL_SENSALIAS: + cil_destroy_alias(*data); + break; + case CIL_SENSALIASACTUAL: + cil_destroy_aliasactual(*data); + break; + case CIL_SENSITIVITYORDER: + cil_destroy_sensitivityorder(*data); + break; + case CIL_SENSCAT: + cil_destroy_senscat(*data); + break; + case CIL_CAT: + cil_destroy_category(*data); + break; + case CIL_CATSET: + cil_destroy_catset(*data); + break; + case CIL_CATALIAS: + cil_destroy_alias(*data); + break; + case CIL_CATALIASACTUAL: + cil_destroy_aliasactual(*data); + break; + case CIL_CATORDER: + cil_destroy_catorder(*data); + break; + case CIL_LEVEL: + cil_destroy_level(*data); + break; + case CIL_LEVELRANGE: + cil_destroy_levelrange(*data); + break; + case CIL_SID: + cil_destroy_sid(*data); + break; + case CIL_SIDORDER: + cil_destroy_sidorder(*data); + break; + case CIL_NAME: + cil_destroy_name(*data); + break; + case CIL_ROLEALLOW: + cil_destroy_roleallow(*data); + break; + case CIL_AVRULE: + case CIL_AVRULEX: + cil_destroy_avrule(*data); + break; + case CIL_PERMISSIONX: + cil_destroy_permissionx(*data); + break; + case CIL_ROLETRANSITION: + cil_destroy_roletransition(*data); + break; + case CIL_TYPE_RULE: + cil_destroy_type_rule(*data); + break; + case CIL_NAMETYPETRANSITION: + cil_destroy_typetransition(*data); + break; + case CIL_RANGETRANSITION: + cil_destroy_rangetransition(*data); + break; + case CIL_CONSTRAIN: + cil_destroy_constrain(*data); + break; + case CIL_MLSCONSTRAIN: + cil_destroy_constrain(*data); + break; + case CIL_VALIDATETRANS: + case CIL_MLSVALIDATETRANS: + cil_destroy_validatetrans(*data); + break; + case CIL_CONTEXT: + cil_destroy_context(*data); + break; + case CIL_IPADDR: + cil_destroy_ipaddr(*data); + break; + case CIL_SIDCONTEXT: + cil_destroy_sidcontext(*data); + break; + case CIL_FSUSE: + cil_destroy_fsuse(*data); + break; + case CIL_FILECON: + cil_destroy_filecon(*data); + break; + case CIL_PORTCON: + cil_destroy_portcon(*data); + break; + case CIL_NODECON: + cil_destroy_nodecon(*data); + break; + case CIL_GENFSCON: + cil_destroy_genfscon(*data); + break; + case CIL_NETIFCON: + cil_destroy_netifcon(*data); + break; + case CIL_PIRQCON: + cil_destroy_pirqcon(*data); + break; + case CIL_IOMEMCON: + cil_destroy_iomemcon(*data); + break; + case CIL_IOPORTCON: + cil_destroy_ioportcon(*data); + break; + case CIL_PCIDEVICECON: + cil_destroy_pcidevicecon(*data); + break; + case CIL_DEVICETREECON: + cil_destroy_devicetreecon(*data); + break; + case CIL_POLICYCAP: + cil_destroy_policycap(*data); + break; + case CIL_DEFAULTUSER: + case CIL_DEFAULTROLE: + case CIL_DEFAULTTYPE: + cil_destroy_default(*data); + break; + case CIL_DEFAULTRANGE: + cil_destroy_defaultrange(*data); + break; + case CIL_HANDLEUNKNOWN: + cil_destroy_handleunknown(*data); + break; + case CIL_MLS: + cil_destroy_mls(*data); + break; + case CIL_SRC_INFO: + cil_destroy_src_info(*data); + break; + case CIL_OP: + case CIL_CONS_OPERAND: + break; + default: + cil_log(CIL_INFO, "Unknown data flavor: %d\n", flavor); + break; + } + + *data = NULL; +} + +int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_index) +{ + if (flavor < CIL_MIN_DECLARATIVE) { + return SEPOL_ERR; + } + + switch(flavor) { + case CIL_BLOCK: + *sym_index = CIL_SYM_BLOCKS; + break; + case CIL_MACRO: + *sym_index = CIL_SYM_BLOCKS; + break; + case CIL_OPTIONAL: + *sym_index = CIL_SYM_BLOCKS; + break; + case CIL_BOOL: + *sym_index = CIL_SYM_BOOLS; + break; + case CIL_TUNABLE: + *sym_index = CIL_SYM_TUNABLES; + break; + case CIL_PERM: + case CIL_MAP_PERM: + *sym_index = CIL_SYM_PERMS; + break; + case CIL_COMMON: + *sym_index = CIL_SYM_COMMONS; + break; + case CIL_CLASS: + case CIL_MAP_CLASS: + *sym_index = CIL_SYM_CLASSES; + break; + case CIL_CLASSPERMISSION: + case CIL_CLASSPERMISSIONSET: + *sym_index = CIL_SYM_CLASSPERMSETS; + break; + case CIL_USER: + case CIL_USERATTRIBUTE: + *sym_index = CIL_SYM_USERS; + break; + case CIL_ROLE: + case CIL_ROLEATTRIBUTE: + *sym_index = CIL_SYM_ROLES; + break; + case CIL_TYPE: + case CIL_TYPEALIAS: + case CIL_TYPEATTRIBUTE: + *sym_index = CIL_SYM_TYPES; + break; + case CIL_SENS: + case CIL_SENSALIAS: + *sym_index = CIL_SYM_SENS; + break; + case CIL_CAT: + case CIL_CATSET: + case CIL_CATALIAS: + *sym_index = CIL_SYM_CATS; + break; + case CIL_LEVEL: + *sym_index = CIL_SYM_LEVELS; + break; + case CIL_LEVELRANGE: + *sym_index = CIL_SYM_LEVELRANGES; + break; + case CIL_SID: + *sym_index = CIL_SYM_SIDS; + break; + case CIL_NAME: + *sym_index = CIL_SYM_NAMES; + break; + case CIL_CONTEXT: + *sym_index = CIL_SYM_CONTEXTS; + break; + case CIL_IPADDR: + *sym_index = CIL_SYM_IPADDRS; + break; + case CIL_POLICYCAP: + *sym_index = CIL_SYM_POLICYCAPS; + break; + case CIL_PERMISSIONX: + *sym_index = CIL_SYM_PERMX; + break; + default: + *sym_index = CIL_SYM_UNKNOWN; + cil_log(CIL_INFO, "Failed to find flavor: %d\n", flavor); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +const char * cil_node_to_string(struct cil_tree_node *node) +{ + switch (node->flavor) { + case CIL_NONE: + return "<none>"; + case CIL_ROOT: + return CIL_KEY_ROOT; + case CIL_NODE: + return CIL_KEY_NODE; + case CIL_STRING: + return "string"; + case CIL_DATUM: + return "<datum>"; + case CIL_LIST: + return "<list>"; + case CIL_LIST_ITEM: + return "<list_item>"; + case CIL_PARAM: + return "<param>"; + case CIL_ARGS: + return "<args>"; + case CIL_BLOCK: + return CIL_KEY_BLOCK; + case CIL_BLOCKINHERIT: + return CIL_KEY_BLOCKINHERIT; + case CIL_BLOCKABSTRACT: + return CIL_KEY_BLOCKABSTRACT; + case CIL_IN: + return CIL_KEY_IN; + case CIL_MACRO: + return CIL_KEY_MACRO; + case CIL_CALL: + return CIL_KEY_CALL; + case CIL_OPTIONAL: + return CIL_KEY_OPTIONAL; + case CIL_BOOL: + return CIL_KEY_BOOL; + case CIL_BOOLEANIF: + return CIL_KEY_BOOLEANIF; + case CIL_TUNABLE: + return CIL_KEY_TUNABLE; + case CIL_TUNABLEIF: + return CIL_KEY_TUNABLEIF; + case CIL_CONDBLOCK: + switch (((struct cil_condblock*)node->data)->flavor) { + case CIL_CONDTRUE: + return CIL_KEY_CONDTRUE; + case CIL_CONDFALSE: + return CIL_KEY_CONDFALSE; + default: + break; + } + break; + case CIL_CONDTRUE: + return CIL_KEY_CONDTRUE; + case CIL_CONDFALSE: + return CIL_KEY_CONDFALSE; + case CIL_PERM: + return CIL_KEY_PERM; + case CIL_COMMON: + return CIL_KEY_COMMON; + case CIL_CLASS: + return CIL_KEY_CLASS; + case CIL_CLASSORDER: + return CIL_KEY_CLASSORDER; + case CIL_MAP_CLASS: + return CIL_KEY_MAP_CLASS; + case CIL_CLASSPERMISSION: + return CIL_KEY_CLASSPERMISSION; + case CIL_CLASSCOMMON: + return CIL_KEY_CLASSCOMMON; + case CIL_CLASSMAPPING: + return CIL_KEY_CLASSMAPPING; + case CIL_CLASSPERMISSIONSET: + return CIL_KEY_CLASSPERMISSIONSET; + case CIL_USER: + return CIL_KEY_USER; + case CIL_USERATTRIBUTE: + return CIL_KEY_USERATTRIBUTE; + case CIL_USERATTRIBUTESET: + return CIL_KEY_USERATTRIBUTESET; + case CIL_USERPREFIX: + return CIL_KEY_USERPREFIX; + case CIL_USERROLE: + return CIL_KEY_USERROLE; + case CIL_USERLEVEL: + return CIL_KEY_USERLEVEL; + case CIL_USERRANGE: + return CIL_KEY_USERRANGE; + case CIL_USERBOUNDS: + return CIL_KEY_USERBOUNDS; + case CIL_SELINUXUSER: + return CIL_KEY_SELINUXUSER; + case CIL_SELINUXUSERDEFAULT: + return CIL_KEY_SELINUXUSERDEFAULT; + case CIL_ROLE: + return CIL_KEY_ROLE; + case CIL_ROLEATTRIBUTE: + return CIL_KEY_ROLEATTRIBUTE; + case CIL_ROLEATTRIBUTESET: + return CIL_KEY_ROLEATTRIBUTESET; + case CIL_ROLETYPE: + return CIL_KEY_ROLETYPE; + case CIL_ROLEBOUNDS: + return CIL_KEY_ROLEBOUNDS; + case CIL_TYPE: + return CIL_KEY_TYPE; + case CIL_TYPEATTRIBUTE: + return CIL_KEY_TYPEATTRIBUTE; + case CIL_TYPEALIAS: + return CIL_KEY_TYPEALIAS; + case CIL_TYPEATTRIBUTESET: + return CIL_KEY_TYPEATTRIBUTESET; + case CIL_TYPEALIASACTUAL: + return CIL_KEY_TYPEALIASACTUAL; + case CIL_TYPEBOUNDS: + return CIL_KEY_TYPEBOUNDS; + case CIL_TYPEPERMISSIVE: + return CIL_KEY_TYPEPERMISSIVE; + case CIL_SENS: + return CIL_KEY_SENSITIVITY; + case CIL_SENSALIAS: + return CIL_KEY_SENSALIAS; + case CIL_SENSALIASACTUAL: + return CIL_KEY_SENSALIASACTUAL; + case CIL_SENSITIVITYORDER: + return CIL_KEY_SENSITIVITYORDER; + case CIL_SENSCAT: + return CIL_KEY_SENSCAT; + case CIL_CAT: + return CIL_KEY_CATEGORY; + case CIL_CATSET: + return CIL_KEY_CATSET; + case CIL_CATALIAS: + return CIL_KEY_CATALIAS; + case CIL_CATALIASACTUAL: + return CIL_KEY_CATALIASACTUAL; + case CIL_CATORDER: + return CIL_KEY_CATORDER; + case CIL_LEVEL: + return CIL_KEY_LEVEL; + case CIL_LEVELRANGE: + return CIL_KEY_LEVELRANGE; + case CIL_SID: + return CIL_KEY_SID; + case CIL_SIDORDER: + return CIL_KEY_SIDORDER; + case CIL_NAME: + return CIL_KEY_NAME; + case CIL_ROLEALLOW: + return CIL_KEY_ROLEALLOW; + case CIL_AVRULE: + switch (((struct cil_avrule *)node->data)->rule_kind) { + case CIL_AVRULE_ALLOWED: + return CIL_KEY_ALLOW; + case CIL_AVRULE_AUDITALLOW: + return CIL_KEY_AUDITALLOW; + case CIL_AVRULE_DONTAUDIT: + return CIL_KEY_DONTAUDIT; + case CIL_AVRULE_NEVERALLOW: + return CIL_KEY_NEVERALLOW; + default: + break; + } + break; + case CIL_AVRULEX: + switch (((struct cil_avrule *)node->data)->rule_kind) { + case CIL_AVRULE_ALLOWED: + return CIL_KEY_ALLOWX; + case CIL_AVRULE_AUDITALLOW: + return CIL_KEY_AUDITALLOWX; + case CIL_AVRULE_DONTAUDIT: + return CIL_KEY_DONTAUDITX; + case CIL_AVRULE_NEVERALLOW: + return CIL_KEY_NEVERALLOWX; + default: + break; + } + break; + case CIL_PERMISSIONX: + return CIL_KEY_PERMISSIONX; + case CIL_ROLETRANSITION: + return CIL_KEY_ROLETRANSITION; + case CIL_TYPE_RULE: + switch (((struct cil_type_rule *)node->data)->rule_kind) { + case CIL_TYPE_TRANSITION: + return CIL_KEY_TYPETRANSITION; + case CIL_TYPE_MEMBER: + return CIL_KEY_TYPEMEMBER; + case CIL_TYPE_CHANGE: + return CIL_KEY_TYPECHANGE; + default: + break; + } + break; + case CIL_NAMETYPETRANSITION: + return CIL_KEY_TYPETRANSITION; + case CIL_RANGETRANSITION: + return CIL_KEY_RANGETRANSITION; + case CIL_CONSTRAIN: + return CIL_KEY_CONSTRAIN; + case CIL_MLSCONSTRAIN: + return CIL_KEY_MLSCONSTRAIN; + case CIL_VALIDATETRANS: + return CIL_KEY_VALIDATETRANS; + case CIL_MLSVALIDATETRANS: + return CIL_KEY_MLSVALIDATETRANS; + case CIL_CONTEXT: + return CIL_KEY_CONTEXT; + case CIL_IPADDR: + return CIL_KEY_IPADDR; + case CIL_SIDCONTEXT: + return CIL_KEY_SIDCONTEXT; + case CIL_FSUSE: + return CIL_KEY_FSUSE; + case CIL_FILECON: + return CIL_KEY_FILECON; + case CIL_PORTCON: + return CIL_KEY_PORTCON; + case CIL_NODECON: + return CIL_KEY_NODECON; + case CIL_GENFSCON: + return CIL_KEY_GENFSCON; + case CIL_NETIFCON: + return CIL_KEY_NETIFCON; + case CIL_PIRQCON: + return CIL_KEY_PIRQCON; + case CIL_IOMEMCON: + return CIL_KEY_IOMEMCON; + case CIL_IOPORTCON: + return CIL_KEY_IOPORTCON; + case CIL_PCIDEVICECON: + return CIL_KEY_PCIDEVICECON; + case CIL_DEVICETREECON: + return CIL_KEY_DEVICETREECON; + case CIL_POLICYCAP: + return CIL_KEY_POLICYCAP; + case CIL_DEFAULTUSER: + return CIL_KEY_DEFAULTUSER; + case CIL_DEFAULTROLE: + return CIL_KEY_DEFAULTROLE; + case CIL_DEFAULTTYPE: + return CIL_KEY_DEFAULTTYPE; + case CIL_DEFAULTRANGE: + return CIL_KEY_DEFAULTRANGE; + case CIL_HANDLEUNKNOWN: + return CIL_KEY_HANDLEUNKNOWN; + case CIL_MLS: + return CIL_KEY_MLS; + case CIL_SRC_INFO: + return CIL_KEY_SRC_INFO; + case CIL_ALL: + return CIL_KEY_ALL; + case CIL_RANGE: + return CIL_KEY_RANGE; + case CIL_AND: + return CIL_KEY_AND; + case CIL_OR: + return CIL_KEY_OR; + case CIL_XOR: + return CIL_KEY_XOR; + case CIL_NOT: + return CIL_KEY_NOT; + case CIL_EQ: + return CIL_KEY_EQ; + case CIL_NEQ: + return CIL_KEY_NEQ; + case CIL_CONS_DOM: + return CIL_KEY_CONS_DOM; + case CIL_CONS_DOMBY: + return CIL_KEY_CONS_DOMBY; + case CIL_CONS_INCOMP: + return CIL_KEY_CONS_INCOMP; + case CIL_CONS_U1: + return CIL_KEY_CONS_U1; + case CIL_CONS_U2: + return CIL_KEY_CONS_U2; + case CIL_CONS_U3: + return CIL_KEY_CONS_U3; + case CIL_CONS_T1: + return CIL_KEY_CONS_T1; + case CIL_CONS_T2: + return CIL_KEY_CONS_T2; + case CIL_CONS_T3: + return CIL_KEY_CONS_T3; + case CIL_CONS_R1: + return CIL_KEY_CONS_R1; + case CIL_CONS_R2: + return CIL_KEY_CONS_R2; + case CIL_CONS_R3: + return CIL_KEY_CONS_R3; + case CIL_CONS_L1: + return CIL_KEY_CONS_L1; + case CIL_CONS_L2: + return CIL_KEY_CONS_L2; + case CIL_CONS_H1: + return CIL_KEY_CONS_H1; + case CIL_CONS_H2: + return CIL_KEY_CONS_H2; + + default: + break; + } + + return "<unknown>"; +} + +#ifdef DISABLE_SYMVER +int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size) +#else +int cil_userprefixes_to_string_nopdb(struct cil_db *db, char **out, size_t *size) +#endif +{ + int rc = SEPOL_ERR; + size_t str_len = 0; + int buf_pos = 0; + char *str_tmp = NULL; + struct cil_list_item *curr; + struct cil_userprefix *userprefix = NULL; + struct cil_user *user = NULL; + + *out = NULL; + + if (db->userprefixes->head == NULL) { + rc = SEPOL_OK; + *size = 0; + goto exit; + } + + cil_list_for_each(curr, db->userprefixes) { + userprefix = curr->data; + user = userprefix->user; + str_len += strlen("user ") + strlen(user->datum.fqn) + strlen(" prefix ") + strlen(userprefix->prefix_str) + 2; + } + + *size = str_len * sizeof(char); + str_len++; + str_tmp = cil_malloc(str_len * sizeof(char)); + *out = str_tmp; + + cil_list_for_each(curr, db->userprefixes) { + userprefix = curr->data; + user = userprefix->user; + + buf_pos = snprintf(str_tmp, str_len, "user %s prefix %s;\n", user->datum.fqn, + userprefix->prefix_str); + str_len -= buf_pos; + str_tmp += buf_pos; + } + + rc = SEPOL_OK; +exit: + return rc; + +} + +#ifndef DISABLE_SYMVER +int cil_userprefixes_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size) +{ + return cil_userprefixes_to_string_nopdb(db, out, size); +} +#endif + +static int cil_cats_to_ebitmap(struct cil_cats *cats, struct ebitmap* cats_ebitmap) +{ + int rc = SEPOL_ERR; + struct cil_list_item *i; + struct cil_list_item *j; + struct cil_cat* cat; + struct cil_catset *cs; + struct cil_tree_node *node; + + if (cats == NULL) { + rc = SEPOL_OK; + goto exit; + } + + cil_list_for_each(i, cats->datum_expr) { + node = DATUM(i->data)->nodes->head->data; + if (node->flavor == CIL_CATSET) { + cs = (struct cil_catset*)i->data; + cil_list_for_each(j, cs->cats->datum_expr) { + cat = (struct cil_cat*)j->data; + rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1); + if (rc != SEPOL_OK) { + goto exit; + } + } + } else { + cat = (struct cil_cat*)i->data; + rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +static int cil_level_equals(struct cil_level *low, struct cil_level *high) +{ + int rc; + struct ebitmap elow; + struct ebitmap ehigh; + + if (strcmp(low->sens->datum.fqn, high->sens->datum.fqn)) { + rc = 0; + goto exit; + } + + ebitmap_init(&elow); + ebitmap_init(&ehigh); + + rc = cil_cats_to_ebitmap(low->cats, &elow); + if (rc != SEPOL_OK) { + goto exit; + } + + rc = cil_cats_to_ebitmap(high->cats, &ehigh); + if (rc != SEPOL_OK) { + goto exit; + } + + return ebitmap_cmp(&elow, &ehigh); + +exit: + return rc; +} + +static int __cil_level_strlen(struct cil_level *lvl) +{ + struct cil_list_item *item; + struct cil_cats *cats = lvl->cats; + int str_len = 0; + char *str1 = NULL; + char *str2 = NULL; + int first = -1; + int last = -1; + + str_len += strlen(lvl->sens->datum.fqn); + + if (cats && cats->datum_expr != NULL) { + str_len++; /* initial ":" */ + cil_list_for_each(item, cats->datum_expr) { + struct cil_cat *cat = item->data; + if (first == -1) { + str1 = cat->datum.fqn; + first = cat->value; + last = first; + } else if (cat->value == last + 1) { + last++; + str2 = cat->datum.fqn; + } else { + if (first == last) { + str_len += strlen(str1) + strlen(cat->datum.fqn) + 1; + } else if (last == first + 1) { + str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2; + } else { + str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2; + } + first = -1; + last = -1; + if (item->next != NULL) { + str_len++; /* space for "," after */ + } + } + } + if (first != -1) { + if (first == last) { + str_len += strlen(str1); + } else if (last == first + 1) { + str_len += strlen(str1) + strlen(str2) + 1; + } else { + str_len += strlen(str1) + strlen(str2) + 1; + } + } + } + + return str_len; +} + +static int __cil_level_to_string(struct cil_level *lvl, char *out) +{ + struct cil_list_item *item; + struct cil_cats *cats = lvl->cats; + int buf_pos = 0; + char *str_tmp = out; + char *str1 = NULL; + char *str2 = NULL; + int first = -1; + int last = -1; + + buf_pos = sprintf(str_tmp, "%s", lvl->sens->datum.fqn); + str_tmp += buf_pos; + + if (cats && cats->datum_expr != NULL) { + buf_pos = sprintf(str_tmp, ":"); + str_tmp += buf_pos; + + cil_list_for_each(item, cats->datum_expr) { + struct cil_cat *cat = item->data; + if (first == -1) { + str1 = cat->datum.fqn; + first = cat->value; + last = first; + } else if (cat->value == last + 1) { + last++; + str2 = cat->datum.fqn; + } else { + if (first == last) { + buf_pos = sprintf(str_tmp, "%s,%s", str1, cat->datum.fqn); + str_tmp += buf_pos; + } else if (last == first + 1) { + buf_pos = sprintf(str_tmp, "%s,%s,%s", str1, str2, cat->datum.fqn); + str_tmp += buf_pos; + } else { + buf_pos = sprintf(str_tmp, "%s.%s,%s",str1, str2, cat->datum.fqn); + str_tmp += buf_pos; + } + first = -1; + last = -1; + if (item->next != NULL) { + buf_pos = sprintf(str_tmp, ","); + str_tmp += buf_pos; + } + } + } + if (first != -1) { + if (first == last) { + buf_pos = sprintf(str_tmp, "%s", str1); + str_tmp += buf_pos; + } else if (last == first + 1) { + buf_pos = sprintf(str_tmp, "%s,%s", str1, str2); + str_tmp += buf_pos; + } else { + buf_pos = sprintf(str_tmp, "%s.%s",str1, str2); + str_tmp += buf_pos; + } + } + } + + return str_tmp - out; +} + +#ifdef DISABLE_SYMVER +int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size) +#else +int cil_selinuxusers_to_string_nopdb(struct cil_db *db, char **out, size_t *size) +#endif +{ + size_t str_len = 0; + int buf_pos = 0; + char *str_tmp = NULL; + struct cil_list_item *curr; + + if (db->selinuxusers->head == NULL) { + *size = 0; + *out = NULL; + return SEPOL_OK; + } + + cil_list_for_each(curr, db->selinuxusers) { + struct cil_selinuxuser *selinuxuser = curr->data; + struct cil_user *user = selinuxuser->user; + + str_len += strlen(selinuxuser->name_str) + strlen(user->datum.fqn) + 1; + + if (db->mls == CIL_TRUE) { + struct cil_levelrange *range = selinuxuser->range; + str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2; + } + + str_len++; + } + + *size = str_len * sizeof(char); + str_tmp = cil_malloc(*size+1); + *out = str_tmp; + + for(curr = db->selinuxusers->head; curr != NULL; curr = curr->next) { + struct cil_selinuxuser *selinuxuser = curr->data; + struct cil_user *user = selinuxuser->user; + + buf_pos = sprintf(str_tmp, "%s:%s", selinuxuser->name_str, user->datum.fqn); + str_tmp += buf_pos; + + if (db->mls == CIL_TRUE) { + struct cil_levelrange *range = selinuxuser->range; + buf_pos = sprintf(str_tmp, ":"); + str_tmp += buf_pos; + buf_pos = __cil_level_to_string(range->low, str_tmp); + str_tmp += buf_pos; + buf_pos = sprintf(str_tmp, "-"); + str_tmp += buf_pos; + buf_pos = __cil_level_to_string(range->high, str_tmp); + str_tmp += buf_pos; + } + + buf_pos = sprintf(str_tmp, "\n"); + str_tmp += buf_pos; + } + + return SEPOL_OK; +} + +#ifndef DISABLE_SYMVER +int cil_selinuxusers_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size) +{ + return cil_selinuxusers_to_string_nopdb(db, out, size); +} +#endif + +#ifdef DISABLE_SYMVER +int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size) +#else +int cil_filecons_to_string_nopdb(struct cil_db *db, char **out, size_t *size) +#endif +{ + uint32_t i = 0; + int buf_pos = 0; + size_t str_len = 0; + char *str_tmp = NULL; + struct cil_sort *filecons = db->filecon; + + for (i = 0; i < filecons->count; i++) { + struct cil_filecon *filecon = filecons->array[i]; + struct cil_context *ctx = filecon->context; + + str_len += strlen(filecon->path_str); + + if (filecon->type != CIL_FILECON_ANY) { + /* If a type is specified, + +2 for type string, +1 for tab */ + str_len += 3; + } + + if (ctx != NULL) { + struct cil_user *user = ctx->user; + struct cil_role *role = ctx->role; + struct cil_type *type = ctx->type; + + str_len += (strlen(user->datum.fqn) + strlen(role->datum.fqn) + strlen(type->datum.fqn) + 3); + + if (db->mls == CIL_TRUE) { + struct cil_levelrange *range = ctx->range; + if (cil_level_equals(range->low, range->high)) { + str_len += __cil_level_strlen(range->low) + 1; + } else { + str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2; + } + } + } else { + str_len += strlen("\t<<none>>"); + } + + str_len++; + } + + *size = str_len * sizeof(char); + str_tmp = cil_malloc(*size+1); + *out = str_tmp; + + for (i = 0; i < filecons->count; i++) { + struct cil_filecon *filecon = filecons->array[i]; + struct cil_context *ctx = filecon->context; + const char *str_type = NULL; + + buf_pos = sprintf(str_tmp, "%s", filecon->path_str); + str_tmp += buf_pos; + + switch(filecon->type) { + case CIL_FILECON_FILE: + str_type = "\t--"; + break; + case CIL_FILECON_DIR: + str_type = "\t-d"; + break; + case CIL_FILECON_CHAR: + str_type = "\t-c"; + break; + case CIL_FILECON_BLOCK: + str_type = "\t-b"; + break; + case CIL_FILECON_SOCKET: + str_type = "\t-s"; + break; + case CIL_FILECON_PIPE: + str_type = "\t-p"; + break; + case CIL_FILECON_SYMLINK: + str_type = "\t-l"; + break; + default: + str_type = ""; + break; + } + buf_pos = sprintf(str_tmp, "%s", str_type); + str_tmp += buf_pos; + + if (ctx != NULL) { + struct cil_user *user = ctx->user; + struct cil_role *role = ctx->role; + struct cil_type *type = ctx->type; + + buf_pos = sprintf(str_tmp, "\t%s:%s:%s", user->datum.fqn, role->datum.fqn, + type->datum.fqn); + str_tmp += buf_pos; + + if (db->mls == CIL_TRUE) { + struct cil_levelrange *range = ctx->range; + buf_pos = sprintf(str_tmp, ":"); + str_tmp += buf_pos; + buf_pos = __cil_level_to_string(range->low, str_tmp); + str_tmp += buf_pos; + + if (!cil_level_equals(range->low, range->high)) { + buf_pos = sprintf(str_tmp, "-"); + str_tmp += buf_pos; + buf_pos = __cil_level_to_string(range->high, str_tmp); + str_tmp += buf_pos; + } + } + } else { + buf_pos = sprintf(str_tmp, "\t<<none>>"); + str_tmp += buf_pos; + } + + buf_pos = sprintf(str_tmp, "\n"); + str_tmp += buf_pos; + } + + return SEPOL_OK; +} + +#ifndef DISABLE_SYMVER +int cil_filecons_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size) +{ + return cil_filecons_to_string_nopdb(db, out, size); +} +#endif + +void cil_set_disable_dontaudit(struct cil_db *db, int disable_dontaudit) +{ + db->disable_dontaudit = disable_dontaudit; +} + +void cil_set_disable_neverallow(struct cil_db *db, int disable_neverallow) +{ + db->disable_neverallow = disable_neverallow; +} + +void cil_set_preserve_tunables(struct cil_db *db, int preserve_tunables) +{ + db->preserve_tunables = preserve_tunables; +} + +int cil_set_handle_unknown(struct cil_db *db, int handle_unknown) +{ + int rc = 0; + + switch (handle_unknown) { + case SEPOL_DENY_UNKNOWN: + case SEPOL_REJECT_UNKNOWN: + case SEPOL_ALLOW_UNKNOWN: + db->handle_unknown = handle_unknown; + break; + default: + cil_log(CIL_ERR, "Unknown value for handle-unknown: %i\n", handle_unknown); + rc = -1; + } + + return rc; +} + +void cil_set_mls(struct cil_db *db, int mls) +{ + db->mls = mls; +} + +void cil_set_target_platform(struct cil_db *db, int target_platform) +{ + db->target_platform = target_platform; +} + +void cil_set_policy_version(struct cil_db *db, int policy_version) +{ + db->policy_version = policy_version; +} + +void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM]) +{ + uint32_t i = 0; + for (i = 0; i < CIL_SYM_NUM; i++) { + cil_symtab_init(&symtab[i], symtab_sizes[i]); + } +} + +void cil_symtab_array_destroy(symtab_t symtab[]) +{ + int i = 0; + for (i = 0; i < CIL_SYM_NUM; i++) { + cil_symtab_destroy(&symtab[i]); + } +} + +void cil_destroy_ast_symtabs(struct cil_tree_node *current) +{ + while (current) { + switch (current->flavor) { + case CIL_BLOCK: + cil_symtab_array_destroy(((struct cil_block*)current->data)->symtab); + break; + case CIL_IN: + cil_symtab_array_destroy(((struct cil_in*)current->data)->symtab); + break; + case CIL_CLASS: + case CIL_COMMON: + case CIL_MAP_CLASS: + cil_symtab_destroy(&((struct cil_class*)current->data)->perms); + break; + case CIL_MACRO: + cil_symtab_array_destroy(((struct cil_macro*)current->data)->symtab); + break; + case CIL_CONDBLOCK: + cil_symtab_array_destroy(((struct cil_condblock*)current->data)->symtab); + break; + default: + break; + } + + if (current->cl_head) { + cil_destroy_ast_symtabs(current->cl_head); + } + + current = current->next; + } +} + +int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index) +{ + struct cil_tree_node *node = ast_node; + *symtab = NULL; + + if (sym_index == CIL_SYM_PERMS) { + /* Class statements are not blocks, so the passed node should be the class */ + if (node->flavor == CIL_CLASS || node->flavor == CIL_MAP_CLASS || + node->flavor == CIL_COMMON) { + *symtab = &((struct cil_class*)node->data)->perms; + return SEPOL_OK; + } + goto exit; + } + + if (sym_index < CIL_SYM_BLOCKS || sym_index >= CIL_SYM_NUM) { + cil_log(CIL_ERR, "Invalid symtab type\n"); + goto exit; + } + + while (node != NULL && *symtab == NULL) { + switch (node->flavor) { + case CIL_ROOT: + *symtab = &((struct cil_root *)node->data)->symtab[sym_index]; + break; + case CIL_BLOCK: + *symtab = &((struct cil_block*)node->data)->symtab[sym_index]; + break; + case CIL_MACRO: + *symtab = &((struct cil_macro*)node->data)->symtab[sym_index]; + break; + case CIL_IN: + /* In blocks only exist before resolving the AST */ + *symtab = &((struct cil_in*)node->data)->symtab[sym_index]; + break; + case CIL_CONDBLOCK: { + if (node->parent->flavor == CIL_TUNABLEIF) { + /* Cond blocks only exist before resolving the AST */ + *symtab = &((struct cil_condblock*)node->data)->symtab[sym_index]; + } else if (node->parent->flavor == CIL_BOOLEANIF) { + node = node->parent->parent; + } + break; + } + default: + node = node->parent; + } + } + + if (*symtab == NULL) { + goto exit; + } + + return SEPOL_OK; + +exit: + cil_tree_log(ast_node, CIL_ERR, "Failed to get symtab from node"); + return SEPOL_ERR; +} + +void cil_sort_init(struct cil_sort **sort) +{ + *sort = cil_malloc(sizeof(**sort)); + + (*sort)->flavor = CIL_NONE; + (*sort)->count = 0; + (*sort)->index = 0; + (*sort)->array = NULL; +} + +void cil_sort_destroy(struct cil_sort **sort) +{ + (*sort)->flavor = CIL_NONE; + (*sort)->count = 0; + (*sort)->index = 0; + if ((*sort)->array != NULL) { + free((*sort)->array); + } + (*sort)->array = NULL; + + free(*sort); + *sort = NULL; +} + +void cil_netifcon_init(struct cil_netifcon **netifcon) +{ + *netifcon = cil_malloc(sizeof(**netifcon)); + + (*netifcon)->interface_str = NULL; + (*netifcon)->if_context_str = NULL; + (*netifcon)->if_context = NULL; + (*netifcon)->packet_context_str = NULL; + (*netifcon)->packet_context = NULL; + (*netifcon)->context_str = NULL; +} + +void cil_context_init(struct cil_context **context) +{ + *context = cil_malloc(sizeof(**context)); + + cil_symtab_datum_init(&(*context)->datum); + (*context)->user_str = NULL; + (*context)->user = NULL; + (*context)->role_str = NULL; + (*context)->role = NULL; + (*context)->type_str = NULL; + (*context)->type = NULL; + (*context)->range_str = NULL; + (*context)->range = NULL; +} + +void cil_level_init(struct cil_level **level) +{ + *level = cil_malloc(sizeof(**level)); + + cil_symtab_datum_init(&(*level)->datum); + (*level)->sens_str = NULL; + (*level)->sens = NULL; + (*level)->cats = NULL; +} + +void cil_levelrange_init(struct cil_levelrange **range) +{ + *range = cil_malloc(sizeof(**range)); + + cil_symtab_datum_init(&(*range)->datum); + (*range)->low_str = NULL; + (*range)->low = NULL; + (*range)->high_str = NULL; + (*range)->high = NULL; +} + +void cil_sens_init(struct cil_sens **sens) +{ + *sens = cil_malloc(sizeof(**sens)); + + cil_symtab_datum_init(&(*sens)->datum); + + (*sens)->cats_list = NULL; + + (*sens)->ordered = CIL_FALSE; +} + +void cil_block_init(struct cil_block **block) +{ + *block = cil_malloc(sizeof(**block)); + + cil_symtab_datum_init(&(*block)->datum); + + cil_symtab_array_init((*block)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK]); + + (*block)->is_abstract = CIL_FALSE; + + (*block)->bi_nodes = NULL; +} + +void cil_blockinherit_init(struct cil_blockinherit **inherit) +{ + *inherit = cil_malloc(sizeof(**inherit)); + (*inherit)->block_str = NULL; + (*inherit)->block = NULL; +} + +void cil_blockabstract_init(struct cil_blockabstract **abstract) +{ + *abstract = cil_malloc(sizeof(**abstract)); + (*abstract)->block_str = NULL; +} + +void cil_in_init(struct cil_in **in) +{ + *in = cil_malloc(sizeof(**in)); + + cil_symtab_array_init((*in)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_IN]); + (*in)->block_str = NULL; +} + +void cil_class_init(struct cil_class **class) +{ + *class = cil_malloc(sizeof(**class)); + + cil_symtab_datum_init(&(*class)->datum); + + cil_symtab_init(&(*class)->perms, CIL_CLASS_SYM_SIZE); + + (*class)->num_perms = 0; + (*class)->common = NULL; + (*class)->ordered = CIL_FALSE; +} + +void cil_classorder_init(struct cil_classorder **classorder) +{ + *classorder = cil_malloc(sizeof(**classorder)); + + (*classorder)->class_list_str = NULL; +} + +void cil_classcommon_init(struct cil_classcommon **classcommon) +{ + *classcommon = cil_malloc(sizeof(**classcommon)); + + (*classcommon)->class_str = NULL; + (*classcommon)->common_str = NULL; +} + +void cil_sid_init(struct cil_sid **sid) +{ + *sid = cil_malloc(sizeof(**sid)); + + cil_symtab_datum_init(&(*sid)->datum); + + (*sid)->ordered = CIL_FALSE; + (*sid)->context = NULL; +} + +void cil_sidcontext_init(struct cil_sidcontext **sidcontext) +{ + *sidcontext = cil_malloc(sizeof(**sidcontext)); + + (*sidcontext)->sid_str = NULL; + (*sidcontext)->context_str = NULL; + (*sidcontext)->context = NULL; +} + +void cil_sidorder_init(struct cil_sidorder **sidorder) +{ + *sidorder = cil_malloc(sizeof(**sidorder)); + + (*sidorder)->sid_list_str = NULL; +} + +void cil_userrole_init(struct cil_userrole **userrole) +{ + *userrole = cil_malloc(sizeof(**userrole)); + + (*userrole)->user_str = NULL; + (*userrole)->user = NULL; + (*userrole)->role_str = NULL; + (*userrole)->role = NULL; +} + +void cil_userprefix_init(struct cil_userprefix **userprefix) +{ + *userprefix = cil_malloc(sizeof(**userprefix)); + + (*userprefix)->user_str = NULL; + (*userprefix)->user = NULL; + (*userprefix)->prefix_str = NULL; +} + +void cil_selinuxuser_init(struct cil_selinuxuser **selinuxuser) +{ + *selinuxuser = cil_malloc(sizeof(**selinuxuser)); + + (*selinuxuser)->name_str = NULL; + (*selinuxuser)->user_str = NULL; + (*selinuxuser)->user = NULL; + (*selinuxuser)->range_str = NULL; + (*selinuxuser)->range = NULL; +} + +void cil_roletype_init(struct cil_roletype **roletype) +{ + *roletype = cil_malloc(sizeof(**roletype)); + + (*roletype)->role_str = NULL; + (*roletype)->role = NULL; + (*roletype)->type_str = NULL; + (*roletype)->type = NULL; +} + +void cil_roleattribute_init(struct cil_roleattribute **attr) +{ + *attr = cil_malloc(sizeof(**attr)); + + cil_symtab_datum_init(&(*attr)->datum); + + (*attr)->expr_list = NULL; + (*attr)->roles = NULL; +} + +void cil_roleattributeset_init(struct cil_roleattributeset **attrset) +{ + *attrset = cil_malloc(sizeof(**attrset)); + + (*attrset)->attr_str = NULL; + (*attrset)->str_expr = NULL; + (*attrset)->datum_expr = NULL; +} + +void cil_typeattribute_init(struct cil_typeattribute **attr) +{ + *attr = cil_malloc(sizeof(**attr)); + + cil_symtab_datum_init(&(*attr)->datum); + + (*attr)->expr_list = NULL; + (*attr)->types = NULL; + (*attr)->used = CIL_FALSE; +} + +void cil_typeattributeset_init(struct cil_typeattributeset **attrset) +{ + *attrset = cil_malloc(sizeof(**attrset)); + + (*attrset)->attr_str = NULL; + (*attrset)->str_expr = NULL; + (*attrset)->datum_expr = NULL; +} + +void cil_alias_init(struct cil_alias **alias) +{ + *alias = cil_malloc(sizeof(**alias)); + + (*alias)->actual = NULL; + + cil_symtab_datum_init(&(*alias)->datum); +} + +void cil_aliasactual_init(struct cil_aliasactual **aliasactual) +{ + *aliasactual = cil_malloc(sizeof(**aliasactual)); + + (*aliasactual)->alias_str = NULL; + (*aliasactual)->actual_str = NULL; +} + +void cil_typepermissive_init(struct cil_typepermissive **typeperm) +{ + *typeperm = cil_malloc(sizeof(**typeperm)); + + (*typeperm)->type_str = NULL; + (*typeperm)->type = NULL; +} + +void cil_name_init(struct cil_name **name) +{ + *name = cil_malloc(sizeof(**name)); + + cil_symtab_datum_init(&(*name)->datum); + (*name)->name_str = NULL; +} + +void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans) +{ + *nametypetrans = cil_malloc(sizeof(**nametypetrans)); + + (*nametypetrans)->src_str = NULL; + (*nametypetrans)->src = NULL; + (*nametypetrans)->tgt_str = NULL; + (*nametypetrans)->tgt = NULL; + (*nametypetrans)->obj_str = NULL; + (*nametypetrans)->obj = NULL; + (*nametypetrans)->name_str = NULL; + (*nametypetrans)->name = NULL; + (*nametypetrans)->result_str = NULL; + (*nametypetrans)->result = NULL; +} + +void cil_rangetransition_init(struct cil_rangetransition **rangetrans) +{ + *rangetrans = cil_malloc(sizeof(**rangetrans)); + + (*rangetrans)->src_str = NULL; + (*rangetrans)->src = NULL; + (*rangetrans)->exec_str = NULL; + (*rangetrans)->exec = NULL; + (*rangetrans)->obj_str = NULL; + (*rangetrans)->obj = NULL; + (*rangetrans)->range_str = NULL; + (*rangetrans)->range = NULL; +} + +void cil_bool_init(struct cil_bool **cilbool) +{ + *cilbool = cil_malloc(sizeof(**cilbool)); + + cil_symtab_datum_init(&(*cilbool)->datum); + (*cilbool)->value = 0; +} + +void cil_tunable_init(struct cil_tunable **ciltun) +{ + *ciltun = cil_malloc(sizeof(**ciltun)); + + cil_symtab_datum_init(&(*ciltun)->datum); + (*ciltun)->value = 0; +} + +void cil_condblock_init(struct cil_condblock **cb) +{ + *cb = cil_malloc(sizeof(**cb)); + + (*cb)->flavor = CIL_NONE; + cil_symtab_array_init((*cb)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_CONDBLOCK]); +} + +void cil_boolif_init(struct cil_booleanif **bif) +{ + *bif = cil_malloc(sizeof(**bif)); + + (*bif)->str_expr = NULL; + (*bif)->datum_expr = NULL; +} + +void cil_tunif_init(struct cil_tunableif **tif) +{ + *tif = cil_malloc(sizeof(**tif)); + + (*tif)->str_expr = NULL; + (*tif)->datum_expr = NULL; +} + +void cil_avrule_init(struct cil_avrule **avrule) +{ + *avrule = cil_malloc(sizeof(**avrule)); + + (*avrule)->is_extended = 0; + (*avrule)->rule_kind = CIL_NONE; + (*avrule)->src_str = NULL; + (*avrule)->src = NULL; + (*avrule)->tgt_str = NULL; + (*avrule)->tgt = NULL; + memset(&((*avrule)->perms), 0, sizeof((*avrule)->perms)); +} + +void cil_permissionx_init(struct cil_permissionx **permx) +{ + *permx = cil_malloc(sizeof(**permx)); + + cil_symtab_datum_init(&(*permx)->datum); + (*permx)->kind = CIL_NONE; + (*permx)->obj_str = NULL; + (*permx)->obj = NULL; + (*permx)->expr_str = NULL; + (*permx)->perms = NULL; +} + +void cil_type_rule_init(struct cil_type_rule **type_rule) +{ + *type_rule = cil_malloc(sizeof(**type_rule)); + + (*type_rule)->rule_kind = CIL_NONE; + (*type_rule)->src_str = NULL; + (*type_rule)->src = NULL; + (*type_rule)->tgt_str = NULL; + (*type_rule)->tgt = NULL; + (*type_rule)->obj_str = NULL; + (*type_rule)->obj = NULL; + (*type_rule)->result_str = NULL; + (*type_rule)->result = NULL; +} + +void cil_roletransition_init(struct cil_roletransition **role_trans) +{ + *role_trans = cil_malloc(sizeof(**role_trans)); + + (*role_trans)->src_str = NULL; + (*role_trans)->src = NULL; + (*role_trans)->tgt_str = NULL; + (*role_trans)->tgt = NULL; + (*role_trans)->obj_str = NULL; + (*role_trans)->obj = NULL; + (*role_trans)->result_str = NULL; + (*role_trans)->result = NULL; +} + +void cil_roleallow_init(struct cil_roleallow **roleallow) +{ + *roleallow = cil_malloc(sizeof(**roleallow)); + + (*roleallow)->src_str = NULL; + (*roleallow)->src = NULL; + (*roleallow)->tgt_str = NULL; + (*roleallow)->tgt = NULL; +} + +void cil_catset_init(struct cil_catset **catset) +{ + *catset = cil_malloc(sizeof(**catset)); + + cil_symtab_datum_init(&(*catset)->datum); + (*catset)->cats = NULL; +} + +void cil_senscat_init(struct cil_senscat **senscat) +{ + *senscat = cil_malloc(sizeof(**senscat)); + + (*senscat)->sens_str = NULL; + (*senscat)->cats = NULL; +} + +void cil_cats_init(struct cil_cats **cats) +{ + *cats = cil_malloc(sizeof(**cats)); + + (*cats)->evaluated = CIL_FALSE; + (*cats)->str_expr = NULL; + (*cats)->datum_expr = NULL; +} + +void cil_filecon_init(struct cil_filecon **filecon) +{ + *filecon = cil_malloc(sizeof(**filecon)); + + (*filecon)->path_str = NULL; + (*filecon)->type = 0; + (*filecon)->context_str = NULL; + (*filecon)->context = NULL; +} + +void cil_portcon_init(struct cil_portcon **portcon) +{ + *portcon = cil_malloc(sizeof(**portcon)); + (*portcon)->proto = 0; + (*portcon)->port_low = 0; + (*portcon)->port_high = 0; + (*portcon)->context_str = NULL; + (*portcon)->context = NULL; +} + +void cil_nodecon_init(struct cil_nodecon **nodecon) +{ + *nodecon = cil_malloc(sizeof(**nodecon)); + + (*nodecon)->addr_str = NULL; + (*nodecon)->addr = NULL; + (*nodecon)->mask_str = NULL; + (*nodecon)->mask = NULL; + (*nodecon)->context_str = NULL; + (*nodecon)->context = NULL; +} + +void cil_genfscon_init(struct cil_genfscon **genfscon) +{ + *genfscon = cil_malloc(sizeof(**genfscon)); + + (*genfscon)->fs_str = NULL; + (*genfscon)->path_str = NULL; + (*genfscon)->context_str = NULL; + (*genfscon)->context = NULL; +} + +void cil_pirqcon_init(struct cil_pirqcon **pirqcon) +{ + *pirqcon = cil_malloc(sizeof(**pirqcon)); + + (*pirqcon)->pirq = 0; + (*pirqcon)->context_str = NULL; + (*pirqcon)->context = NULL; +} + +void cil_iomemcon_init(struct cil_iomemcon **iomemcon) +{ + *iomemcon = cil_malloc(sizeof(**iomemcon)); + + (*iomemcon)->iomem_low = 0; + (*iomemcon)->iomem_high = 0; + (*iomemcon)->context_str = NULL; + (*iomemcon)->context = NULL; +} + +void cil_ioportcon_init(struct cil_ioportcon **ioportcon) +{ + *ioportcon = cil_malloc(sizeof(**ioportcon)); + + (*ioportcon)->context_str = NULL; + (*ioportcon)->context = NULL; +} + +void cil_pcidevicecon_init(struct cil_pcidevicecon **pcidevicecon) +{ + *pcidevicecon = cil_malloc(sizeof(**pcidevicecon)); + + (*pcidevicecon)->dev = 0; + (*pcidevicecon)->context_str = NULL; + (*pcidevicecon)->context = NULL; +} + +void cil_devicetreecon_init(struct cil_devicetreecon **dtcon) +{ + *dtcon = cil_malloc(sizeof(**dtcon)); + + (*dtcon)->path = NULL; + (*dtcon)->context_str = NULL; + (*dtcon)->context = NULL; +} + +void cil_fsuse_init(struct cil_fsuse **fsuse) +{ + *fsuse = cil_malloc(sizeof(**fsuse)); + + (*fsuse)->type = 0; + (*fsuse)->fs_str = NULL; + (*fsuse)->context_str = NULL; + (*fsuse)->context = NULL; +} + +void cil_constrain_init(struct cil_constrain **constrain) +{ + *constrain = cil_malloc(sizeof(**constrain)); + + (*constrain)->classperms = NULL; + (*constrain)->str_expr = NULL; + (*constrain)->datum_expr = NULL; +} + +void cil_validatetrans_init(struct cil_validatetrans **validtrans) +{ + *validtrans = cil_malloc(sizeof(**validtrans)); + + (*validtrans)->class_str = NULL; + (*validtrans)->class = NULL; + (*validtrans)->str_expr = NULL; + (*validtrans)->datum_expr = NULL; +} + +void cil_ipaddr_init(struct cil_ipaddr **ipaddr) +{ + *ipaddr = cil_malloc(sizeof(**ipaddr)); + + cil_symtab_datum_init(&(*ipaddr)->datum); + memset(&(*ipaddr)->ip, 0, sizeof((*ipaddr)->ip)); +} + +void cil_perm_init(struct cil_perm **perm) +{ + *perm = cil_malloc(sizeof(**perm)); + + cil_symtab_datum_init(&(*perm)->datum); + (*perm)->value = 0; + (*perm)->classperms = NULL; +} + +void cil_classpermission_init(struct cil_classpermission **cp) +{ + *cp = cil_malloc(sizeof(**cp)); + + cil_symtab_datum_init(&(*cp)->datum); + (*cp)->classperms = NULL; +} + +void cil_classpermissionset_init(struct cil_classpermissionset **cps) +{ + *cps = cil_malloc(sizeof(**cps)); + + (*cps)->set_str = NULL; + (*cps)->classperms = NULL; +} + +void cil_classperms_set_init(struct cil_classperms_set **cp_set) +{ + *cp_set = cil_malloc(sizeof(**cp_set)); + (*cp_set)->set_str = NULL; + (*cp_set)->set = NULL; +} + +void cil_classperms_init(struct cil_classperms **cp) +{ + *cp = cil_malloc(sizeof(**cp)); + (*cp)->class_str = NULL; + (*cp)->class = NULL; + (*cp)->perm_strs = NULL; + (*cp)->perms = NULL; +} + +void cil_classmapping_init(struct cil_classmapping **mapping) +{ + *mapping = cil_malloc(sizeof(**mapping)); + + (*mapping)->map_class_str = NULL; + (*mapping)->map_perm_str = NULL; + (*mapping)->classperms = NULL; +} + +void cil_user_init(struct cil_user **user) +{ + *user = cil_malloc(sizeof(**user)); + + cil_symtab_datum_init(&(*user)->datum); + (*user)->bounds = NULL; + (*user)->roles = NULL; + (*user)->dftlevel = NULL; + (*user)->range = NULL; + (*user)->value = 0; +} + +void cil_userattribute_init(struct cil_userattribute **attr) +{ + *attr = cil_malloc(sizeof(**attr)); + + cil_symtab_datum_init(&(*attr)->datum); + + (*attr)->expr_list = NULL; + (*attr)->users = NULL; +} + +void cil_userattributeset_init(struct cil_userattributeset **attrset) +{ + *attrset = cil_malloc(sizeof(**attrset)); + + (*attrset)->attr_str = NULL; + (*attrset)->str_expr = NULL; + (*attrset)->datum_expr = NULL; +} + +void cil_userlevel_init(struct cil_userlevel **usrlvl) +{ + *usrlvl = cil_malloc(sizeof(**usrlvl)); + + (*usrlvl)->user_str = NULL; + (*usrlvl)->level_str = NULL; + (*usrlvl)->level = NULL; +} + +void cil_userrange_init(struct cil_userrange **userrange) +{ + *userrange = cil_malloc(sizeof(**userrange)); + + (*userrange)->user_str = NULL; + (*userrange)->range_str = NULL; + (*userrange)->range = NULL; +} + +void cil_role_init(struct cil_role **role) +{ + *role = cil_malloc(sizeof(**role)); + + cil_symtab_datum_init(&(*role)->datum); + (*role)->bounds = NULL; + (*role)->types = NULL; + (*role)->value = 0; +} + +void cil_type_init(struct cil_type **type) +{ + *type = cil_malloc(sizeof(**type)); + + cil_symtab_datum_init(&(*type)->datum); + (*type)->bounds = NULL; + (*type)->value = 0; +} + +void cil_cat_init(struct cil_cat **cat) +{ + *cat = cil_malloc(sizeof(**cat)); + + cil_symtab_datum_init(&(*cat)->datum); + (*cat)->ordered = CIL_FALSE; + (*cat)->value = 0; +} + +void cil_catorder_init(struct cil_catorder **catorder) +{ + *catorder = cil_malloc(sizeof(**catorder)); + + (*catorder)->cat_list_str = NULL; +} + +void cil_sensorder_init(struct cil_sensorder **sensorder) +{ + *sensorder = cil_malloc(sizeof(**sensorder)); + + (*sensorder)->sens_list_str = NULL; +} + +void cil_args_init(struct cil_args **args) +{ + *args = cil_malloc(sizeof(**args)); + (*args)->arg_str = NULL; + (*args)->arg = NULL; + (*args)->param_str = NULL; + (*args)->flavor = CIL_NONE; +} + +void cil_call_init(struct cil_call **call) +{ + *call = cil_malloc(sizeof(**call)); + + (*call)->macro_str = NULL; + (*call)->macro = NULL; + (*call)->args_tree = NULL; + (*call)->args = NULL; + (*call)->copied = 0; +} + +void cil_optional_init(struct cil_optional **optional) +{ + *optional = cil_malloc(sizeof(**optional)); + (*optional)->enabled = CIL_TRUE; + cil_symtab_datum_init(&(*optional)->datum); +} + +void cil_param_init(struct cil_param **param) +{ + *param = cil_malloc(sizeof(**param)); + + (*param)->str = NULL; + (*param)->flavor = CIL_NONE; +} + +void cil_macro_init(struct cil_macro **macro) +{ + *macro = cil_malloc(sizeof(**macro)); + + cil_symtab_datum_init(&(*macro)->datum); + cil_symtab_array_init((*macro)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_MACRO]); + (*macro)->params = NULL; +} + +void cil_policycap_init(struct cil_policycap **policycap) +{ + *policycap = cil_malloc(sizeof(**policycap)); + + cil_symtab_datum_init(&(*policycap)->datum); +} + +void cil_bounds_init(struct cil_bounds **bounds) +{ + *bounds = cil_malloc(sizeof(**bounds)); + + (*bounds)->parent_str = NULL; + (*bounds)->child_str = NULL; +} + +void cil_default_init(struct cil_default **def) +{ + *def = cil_malloc(sizeof(**def)); + + (*def)->flavor = CIL_NONE; + (*def)->class_strs = NULL; + (*def)->class_datums = NULL; +} + +void cil_defaultrange_init(struct cil_defaultrange **def) +{ + *def = cil_malloc(sizeof(**def)); + + (*def)->class_strs = NULL; + (*def)->class_datums = NULL; +} + +void cil_handleunknown_init(struct cil_handleunknown **unk) +{ + *unk = cil_malloc(sizeof(**unk)); +} + +void cil_mls_init(struct cil_mls **mls) +{ + *mls = cil_malloc(sizeof(**mls)); + (*mls)->value = 0; +} + +void cil_src_info_init(struct cil_src_info **info) +{ + *info = cil_malloc(sizeof(**info)); + (*info)->is_cil = 0; + (*info)->path = NULL; +}
diff --git a/selinux/libsepol/cil/src/cil_binary.c b/selinux/libsepol/cil/src/cil_binary.c new file mode 100644 index 0000000..5d03127 --- /dev/null +++ b/selinux/libsepol/cil/src/cil_binary.c
@@ -0,0 +1,4808 @@ +/* + * Copyright 2011 Tresys Technology, LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those + * of the authors and should not be interpreted as representing official policies, + * either expressed or implied, of Tresys Technology, LLC. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <netinet/in.h> +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/polcaps.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/constraint.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/hierarchy.h> + +#include "cil_internal.h" +#include "cil_flavor.h" +#include "cil_log.h" +#include "cil_mem.h" +#include "cil_tree.h" +#include "cil_binary.h" +#include "cil_symtab.h" +#include "cil_find.h" + +/* There are 44000 filename_trans in current fedora policy. 1.33 times this is the recommended + * size of a hashtable. The next power of 2 of this is 2 ** 16. + */ +#define FILENAME_TRANS_TABLE_SIZE (1 << 16) +#define RANGE_TRANS_TABLE_SIZE (1 << 13) +#define ROLE_TRANS_TABLE_SIZE (1 << 10) +#define AVRULEX_TABLE_SIZE (1 << 10) +#define PERMS_PER_CLASS 32 + +struct cil_args_binary { + const struct cil_db *db; + policydb_t *pdb; + struct cil_list *neverallows; + int pass; + hashtab_t filename_trans_table; + hashtab_t range_trans_table; + hashtab_t role_trans_table; + hashtab_t avrulex_ioctl_table; + void **type_value_to_cil; +}; + +struct cil_args_booleanif { + const struct cil_db *db; + policydb_t *pdb; + cond_node_t *cond_node; + enum cil_flavor cond_flavor; + hashtab_t filename_trans_table; +}; + +static int __cil_get_sepol_user_datum(policydb_t *pdb, struct cil_symtab_datum *datum, user_datum_t **sepol_user) +{ + *sepol_user = hashtab_search(pdb->p_users.table, datum->fqn); + if (*sepol_user == NULL) { + cil_log(CIL_INFO, "Failed to find user %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_get_sepol_role_datum(policydb_t *pdb, struct cil_symtab_datum *datum, role_datum_t **sepol_role) +{ + *sepol_role = hashtab_search(pdb->p_roles.table, datum->fqn); + if (*sepol_role == NULL) { + cil_log(CIL_INFO, "Failed to find role %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_get_sepol_type_datum(policydb_t *pdb, struct cil_symtab_datum *datum, type_datum_t **sepol_type) +{ + *sepol_type = hashtab_search(pdb->p_types.table, datum->fqn); + if (*sepol_type == NULL) { + cil_log(CIL_INFO, "Failed to find type %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_get_sepol_class_datum(policydb_t *pdb, struct cil_symtab_datum *datum, class_datum_t **sepol_class) +{ + *sepol_class = hashtab_search(pdb->p_classes.table, datum->fqn); + if (*sepol_class == NULL) { + cil_log(CIL_INFO, "Failed to find class %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_get_sepol_cat_datum(policydb_t *pdb, struct cil_symtab_datum *datum, cat_datum_t **sepol_cat) +{ + *sepol_cat = hashtab_search(pdb->p_cats.table, datum->fqn); + if (*sepol_cat == NULL) { + cil_log(CIL_INFO, "Failed to find category %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_get_sepol_level_datum(policydb_t *pdb, struct cil_symtab_datum *datum, level_datum_t **sepol_level) +{ + *sepol_level = hashtab_search(pdb->p_levels.table, datum->fqn); + if (*sepol_level == NULL) { + cil_log(CIL_INFO, "Failed to find level %s in sepol hashtab\n", datum->fqn); + return SEPOL_ERR; + } + + return SEPOL_OK; +} + +static int __cil_expand_user(struct cil_symtab_datum *datum, ebitmap_t *new) +{ + struct cil_tree_node *node = datum->nodes->head->data; + struct cil_user *user = NULL; + struct cil_userattribute *attr = NULL; + + if (node->flavor == CIL_USERATTRIBUTE) { + attr = (struct cil_userattribute *)datum; + if (ebitmap_cpy(new, attr->users)) { + cil_log(CIL_ERR, "Failed to copy user bits\n"); + goto exit; + } + } else { + user = (struct cil_user *)datum; + ebitmap_init(new); + if (ebitmap_set_bit(new, user->value, 1)) { + cil_log(CIL_ERR, "Failed to set user bit\n"); + ebitmap_destroy(new); + goto exit; + } + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static int __cil_expand_role(struct cil_symtab_datum *datum, ebitmap_t *new) +{ + struct cil_tree_node *node = datum->nodes->head->data; + + if (node->flavor == CIL_ROLEATTRIBUTE) { + struct cil_roleattribute *attr = (struct cil_roleattribute *)datum; + if (ebitmap_cpy(new, attr->roles)) { + cil_log(CIL_ERR, "Failed to copy role bits\n"); + goto exit; + } + } else { + struct cil_role *role = (struct cil_role *)datum; + ebitmap_init(new); + if (ebitmap_set_bit(new, role->value, 1)) { + cil_log(CIL_ERR, "Failed to set role bit\n"); + ebitmap_destroy(new); + goto exit; + } + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static int __cil_expand_type(struct cil_symtab_datum *datum, ebitmap_t *new) +{ + struct cil_tree_node *node = datum->nodes->head->data; + + if (node->flavor == CIL_TYPEATTRIBUTE) { + struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; + if (ebitmap_cpy(new, attr->types)) { + cil_log(CIL_ERR, "Failed to copy type bits\n"); + goto exit; + } + } else { + struct cil_type *type = (struct cil_type *)datum; + ebitmap_init(new); + if (ebitmap_set_bit(new, type->value, 1)) { + cil_log(CIL_ERR, "Failed to set type bit\n"); + ebitmap_destroy(new); + goto exit; + } + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static ocontext_t *cil_add_ocontext(ocontext_t **head, ocontext_t **tail) +{ + ocontext_t *new = cil_malloc(sizeof(ocontext_t)); + memset(new, 0, sizeof(ocontext_t)); + if (*tail) { + (*tail)->next = new; + } else { + *head = new; + } + *tail = new; + + return new; +} + +int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + struct cil_tree_node *node = cil_common->datum.nodes->head->data; + struct cil_tree_node *cil_perm = node->cl_head; + common_datum_t *sepol_common = cil_malloc(sizeof(*sepol_common)); + memset(sepol_common, 0, sizeof(common_datum_t)); + + key = cil_strdup(cil_common->datum.fqn); + rc = symtab_insert(pdb, SYM_COMMONS, key, sepol_common, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + free(sepol_common); + goto exit; + } + sepol_common->s.value = value; + + rc = symtab_init(&sepol_common->permissions, PERM_SYMTAB_SIZE); + if (rc != SEPOL_OK) { + goto exit; + } + + while (cil_perm != NULL) { + struct cil_perm *curr = cil_perm->data; + perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm)); + memset(sepol_perm, 0, sizeof(perm_datum_t)); + + key = cil_strdup(curr->datum.fqn); + rc = hashtab_insert(sepol_common->permissions.table, key, sepol_perm); + if (rc != SEPOL_OK) { + free(sepol_perm); + goto exit; + } + sepol_perm->s.value = sepol_common->permissions.nprim + 1; + sepol_common->permissions.nprim++; + cil_perm = cil_perm->next; + } + + *common_out = sepol_common; + + return SEPOL_OK; + +exit: + free(key); + return rc; +} + +int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) +{ + int rc = SEPOL_ERR; + struct cil_list_item *curr_class; + + cil_list_for_each(curr_class, db->classorder) { + struct cil_class *cil_class = curr_class->data; + uint32_t value = 0; + char *key = NULL; + int class_index; + struct cil_tree_node *curr; + common_datum_t *sepol_common = NULL; + class_datum_t *sepol_class = cil_malloc(sizeof(*sepol_class)); + memset(sepol_class, 0, sizeof(class_datum_t)); + + key = cil_strdup(cil_class->datum.fqn); + rc = symtab_insert(pdb, SYM_CLASSES, key, sepol_class, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + free(sepol_class); + free(key); + goto exit; + } + sepol_class->s.value = value; + class_index = value; + class_value_to_cil[class_index] = cil_class; + + rc = symtab_init(&sepol_class->permissions, PERM_SYMTAB_SIZE); + if (rc != SEPOL_OK) { + goto exit; + } + + if (cil_class->common != NULL) { + int i; + struct cil_class *cil_common = cil_class->common; + + key = cil_class->common->datum.fqn; + sepol_common = hashtab_search(pdb->p_commons.table, key); + if (sepol_common == NULL) { + rc = cil_common_to_policydb(pdb, cil_common, &sepol_common); + if (rc != SEPOL_OK) { + goto exit; + } + } + sepol_class->comdatum = sepol_common; + sepol_class->comkey = cil_strdup(key); + sepol_class->permissions.nprim += sepol_common->permissions.nprim; + + for (curr = NODE(cil_class->common)->cl_head, i = 1; curr; curr = curr->next, i++) { + struct cil_perm *cil_perm = curr->data; + perm_value_to_cil[class_index][i] = cil_perm; + } + } + + for (curr = NODE(cil_class)->cl_head; curr; curr = curr->next) { + struct cil_perm *cil_perm = curr->data; + perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm)); + memset(sepol_perm, 0, sizeof(perm_datum_t)); + + key = cil_strdup(cil_perm->datum.fqn); + rc = hashtab_insert(sepol_class->permissions.table, key, sepol_perm); + if (rc != SEPOL_OK) { + free(sepol_perm); + free(key); + goto exit; + } + sepol_perm->s.value = sepol_class->permissions.nprim + 1; + sepol_class->permissions.nprim++; + perm_value_to_cil[class_index][sepol_perm->s.value] = cil_perm; + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + role_datum_t *sepol_role = cil_malloc(sizeof(*sepol_role)); + role_datum_init(sepol_role); + + if (cil_role->datum.fqn == CIL_KEY_OBJECT_R) { + /* special case + * object_r defaults to 1 in libsepol symtab */ + rc = SEPOL_OK; + goto exit; + } + + key = cil_strdup(cil_role->datum.fqn); + rc = symtab_insert(pdb, SYM_ROLES, (hashtab_key_t)key, sepol_role, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + if (ebitmap_set_bit(&sepol_role->dominates, value - 1, 1)) { + cil_log(CIL_INFO, "Failed to set dominates bit for role\n"); + rc = SEPOL_ERR; + goto exit; + } + sepol_role->s.value = value; + return SEPOL_OK; + +exit: + free(key); + role_datum_destroy(sepol_role); + free(sepol_role); + return rc; +} + +int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role) +{ + int rc = SEPOL_ERR; + role_datum_t *sepol_role = NULL; + role_datum_t *sepol_parent = NULL; + + if (cil_role->bounds) { + rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role), &sepol_role); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role->bounds), &sepol_parent); + if (rc != SEPOL_OK) goto exit; + + sepol_role->bounds = sepol_parent->s.value; + } + + return SEPOL_OK; + +exit: + cil_log(CIL_ERR, "Failed to insert role bounds for role %s\n", cil_role->datum.fqn); + return SEPOL_ERR; +} + +int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role) +{ + int rc = SEPOL_ERR; + + if (role->types) { + role_datum_t *sepol_role = NULL; + type_datum_t *sepol_type = NULL; + ebitmap_node_t *tnode; + unsigned int i; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(role), &sepol_role); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(role->types, tnode, i) { + if (!ebitmap_get_bit(role->types, i)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + if (ebitmap_set_bit(&sepol_role->types.types, sepol_type->s.value - 1, 1)) { + cil_log(CIL_INFO, "Failed to set type bit for role\n"); + rc = SEPOL_ERR; + goto exit; + } + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + type_datum_t *sepol_type = cil_malloc(sizeof(*sepol_type)); + type_datum_init(sepol_type); + + sepol_type->flavor = TYPE_TYPE; + + key = cil_strdup(cil_type->datum.fqn); + rc = symtab_insert(pdb, SYM_TYPES, key, sepol_type, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_type->s.value = value; + sepol_type->primary = 1; + + type_value_to_cil[value] = cil_type; + + return SEPOL_OK; + +exit: + free(key); + type_datum_destroy(sepol_type); + free(sepol_type); + return rc; +} + +int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type) +{ + int rc = SEPOL_ERR; + type_datum_t *sepol_type = NULL; + type_datum_t *sepol_parent = NULL; + + if (cil_type->bounds) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type->bounds), &sepol_parent); + if (rc != SEPOL_OK) goto exit; + + sepol_type->bounds = sepol_parent->s.value; + } + + return SEPOL_OK; + +exit: + cil_log(CIL_ERR, "Failed to insert type bounds for type %s\n", cil_type->datum.fqn); + return SEPOL_ERR; +} + +int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) +{ + int rc = SEPOL_ERR; + char *key = NULL; + type_datum_t *sepol_type = NULL; + type_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias)); + type_datum_init(sepol_alias); + + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_alias->actual), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + sepol_alias->flavor = TYPE_TYPE; + + key = cil_strdup(cil_alias->datum.fqn); + rc = symtab_insert(pdb, SYM_TYPES, key, sepol_alias, SCOPE_DECL, 0, NULL); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_alias->s.value = sepol_type->s.value; + sepol_alias->primary = 0; + + return SEPOL_OK; + +exit: + free(key); + type_datum_destroy(sepol_alias); + free(sepol_alias); + return rc; +} + +int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm) +{ + int rc = SEPOL_ERR; + type_datum_t *sepol_type = NULL; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_typeperm->type), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + if (ebitmap_set_bit(&pdb->permissive_map, sepol_type->s.value, 1)) { + goto exit; + } + + return SEPOL_OK; + +exit: + type_datum_destroy(sepol_type); + free(sepol_type); + return rc; + +} + +int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + type_datum_t *sepol_attr = NULL; + + if (cil_attr->used == CIL_FALSE) { + return SEPOL_OK; + } + + sepol_attr = cil_malloc(sizeof(*sepol_attr)); + type_datum_init(sepol_attr); + + sepol_attr->flavor = TYPE_ATTRIB; + + key = cil_strdup(cil_attr->datum.fqn); + rc = symtab_insert(pdb, SYM_TYPES, key, sepol_attr, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_attr->s.value = value; + sepol_attr->primary = 1; + + type_value_to_cil[value] = cil_attr; + + return SEPOL_OK; + +exit: + type_datum_destroy(sepol_attr); + free(sepol_attr); + return rc; +} + +int __cil_typeattr_bitmap_init(policydb_t *pdb) +{ + int rc = SEPOL_ERR; + + pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + + uint32_t i = 0; + for (i = 0; i < pdb->p_types.nprim; i++) { + ebitmap_init(&pdb->type_attr_map[i]); + ebitmap_init(&pdb->attr_type_map[i]); + if (ebitmap_set_bit(&pdb->type_attr_map[i], i, 1)) { + rc = SEPOL_ERR; + goto exit; + } + if (pdb->type_val_to_struct[i] && pdb->type_val_to_struct[i]->flavor != TYPE_ATTRIB) { + if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) { + rc = SEPOL_ERR; + goto exit; + } + } + + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *db, struct cil_typeattribute *cil_attr) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + type_datum_t *sepol_type = NULL; + ebitmap_node_t *tnode; + unsigned int i; + + if (cil_attr->used == CIL_FALSE) { + return SEPOL_OK; + } + + if (pdb->type_attr_map == NULL) { + rc = __cil_typeattr_bitmap_init(pdb); + if (rc != SEPOL_OK) { + goto exit; + } + } + + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_attr), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + value = sepol_type->s.value; + + ebitmap_for_each_bit(cil_attr->types, tnode, i) { + if (!ebitmap_get_bit(cil_attr->types, i)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + ebitmap_set_bit(&pdb->type_attr_map[sepol_type->s.value - 1], value - 1, 1); + ebitmap_set_bit(&pdb->attr_type_map[value - 1], sepol_type->s.value - 1, 1); + } + + rc = SEPOL_OK; +exit: + return rc; +} + +int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap) +{ + int rc = SEPOL_ERR; + int capnum; + + capnum = sepol_polcap_getnum(cil_polcap->datum.fqn); + if (capnum == -1) { + goto exit; + } + + if (ebitmap_set_bit(&pdb->policycaps, capnum, 1)) { + goto exit; + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + user_datum_t *sepol_user = cil_malloc(sizeof(*sepol_user)); + user_datum_init(sepol_user); + + key = cil_strdup(cil_user->datum.fqn); + rc = symtab_insert(pdb, SYM_USERS, key, sepol_user, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_user->s.value = value; + + return SEPOL_OK; + +exit: + free(key); + user_datum_destroy(sepol_user); + free(sepol_user); + return rc; +} + +int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user) +{ + int rc = SEPOL_ERR; + user_datum_t *sepol_user = NULL; + user_datum_t *sepol_parent = NULL; + + if (cil_user->bounds) { + rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user->bounds), &sepol_parent); + if (rc != SEPOL_OK) goto exit; + + sepol_user->bounds = sepol_parent->s.value; + } + + return SEPOL_OK; + +exit: + cil_log(CIL_ERR, "Failed to insert user bounds for user %s\n", cil_user->datum.fqn); + return SEPOL_ERR; +} + +int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user) +{ + int rc = SEPOL_ERR; + user_datum_t *sepol_user = NULL; + role_datum_t *sepol_role = NULL; + ebitmap_node_t *rnode = NULL; + unsigned int i; + + if (user->roles) { + rc = __cil_get_sepol_user_datum(pdb, DATUM(user), &sepol_user); + if (rc != SEPOL_OK) { + goto exit; + } + + ebitmap_for_each_bit(user->roles, rnode, i) { + if (!ebitmap_get_bit(user->roles, i)) { + continue; + } + + rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role); + if (rc != SEPOL_OK) { + goto exit; + } + + if (ebitmap_set_bit(&sepol_user->roles.roles, sepol_role->s.value - 1, 1)) { + cil_log(CIL_INFO, "Failed to set role bit for user\n"); + rc = SEPOL_ERR; + goto exit; + } + } + } + + rc = SEPOL_OK; + +exit: + return rc; +} + +int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + cond_bool_datum_t *sepol_bool = cil_malloc(sizeof(*sepol_bool)); + memset(sepol_bool, 0, sizeof(cond_bool_datum_t)); + + key = cil_strdup(cil_bool->datum.fqn); + rc = symtab_insert(pdb, SYM_BOOLS, key, sepol_bool, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_bool->s.value = value; + sepol_bool->state = cil_bool->value; + + return SEPOL_OK; + +exit: + free(key); + free(sepol_bool); + return rc; +} + +int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + struct cil_list_item *curr_cat; + struct cil_cat *cil_cat = NULL; + cat_datum_t *sepol_cat = NULL; + + cil_list_for_each(curr_cat, db->catorder) { + cil_cat = curr_cat->data; + sepol_cat = cil_malloc(sizeof(*sepol_cat)); + cat_datum_init(sepol_cat); + + key = cil_strdup(cil_cat->datum.fqn); + rc = symtab_insert(pdb, SYM_CATS, key, sepol_cat, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_cat->s.value = value; + } + + return SEPOL_OK; + +exit: + free(key); + cat_datum_destroy(sepol_cat); + free(sepol_cat); + return rc; +} + +int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) +{ + int rc = SEPOL_ERR; + char *key = NULL; + cat_datum_t *sepol_cat; + cat_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_cat)); + cat_datum_init(sepol_alias); + + rc = __cil_get_sepol_cat_datum(pdb, DATUM(cil_alias->actual), &sepol_cat); + if (rc != SEPOL_OK) goto exit; + + key = cil_strdup(cil_alias->datum.fqn); + rc = symtab_insert(pdb, SYM_CATS, key, sepol_alias, SCOPE_DECL, 0, NULL); + if (rc != SEPOL_OK) { + free(key); + goto exit; + } + sepol_alias->s.value = sepol_cat->s.value; + sepol_alias->isalias = 1; + + return SEPOL_OK; + +exit: + free(key); + cat_datum_destroy(sepol_alias); + free(sepol_alias); + return rc; +} + +int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db) +{ + int rc = SEPOL_ERR; + uint32_t value = 0; + char *key = NULL; + struct cil_list_item *curr; + struct cil_sens *cil_sens = NULL; + level_datum_t *sepol_level = NULL; + mls_level_t *mls_level = NULL; + + cil_list_for_each(curr, db->sensitivityorder) { + cil_sens = curr->data; + sepol_level = cil_malloc(sizeof(*sepol_level)); + mls_level = cil_malloc(sizeof(*mls_level)); + level_datum_init(sepol_level); + mls_level_init(mls_level); + + key = cil_strdup(cil_sens->datum.fqn); + rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_level, SCOPE_DECL, 0, &value); + if (rc != SEPOL_OK) { + goto exit; + } + mls_level->sens = value; + sepol_level->level = mls_level; + } + + return SEPOL_OK; + +exit: + level_datum_destroy(sepol_level); + mls_level_destroy(mls_level); + free(sepol_level); + free(mls_level); + free(key); + return rc; +} + +int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) +{ + int rc = SEPOL_ERR; + char *key = NULL; + mls_level_t *mls_level = NULL; + level_datum_t *sepol_level = NULL; + level_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias)); + level_datum_init(sepol_alias); + + rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_alias->actual), &sepol_level); + if (rc != SEPOL_OK) goto exit; + + key = cil_strdup(cil_alias->datum.fqn); + rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_alias, SCOPE_DECL, 0, NULL); + if (rc != SEPOL_OK) { + goto exit; + } + + mls_level = cil_malloc(sizeof(*mls_level)); + mls_level_init(mls_level); + + rc = mls_level_cpy(mls_level, sepol_level->level); + if (rc != SEPOL_OK) { + goto exit; + } + sepol_alias->level = mls_level; + sepol_alias->defined = 1; + sepol_alias->isalias = 1; + + return SEPOL_OK; + +exit: + level_datum_destroy(sepol_alias); + free(sepol_level); + free(key); + return rc; +} + +int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_OK; + avtab_ptr_t avtab_ptr = NULL; + cond_av_list_t *cond_list = NULL; + + avtab_ptr = avtab_insert_nonunique(avtab, avtab_key, avtab_datum); + if (!avtab_ptr) { + rc = SEPOL_ERR; + goto exit; + } + + // parse_context needs to be non-NULL for conditional rules to be + // written to the binary. it is normally used for finding duplicates, + // but cil checks that earlier, so we don't use it. it just needs to be + // set + avtab_ptr->parse_context = (void*)1; + + cond_list = cil_malloc(sizeof(cond_av_list_t)); + memset(cond_list, 0, sizeof(cond_av_list_t)); + + cond_list->node = avtab_ptr; + + if (cond_flavor == CIL_CONDTRUE) { + cond_list->next = cond_node->true_list; + cond_node->true_list = cond_list; + } else { + cond_list->next = cond_node->false_list; + cond_node->false_list = cond_list; + } + +exit: + return rc; +} + +avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list) +{ + cond_av_list_t *cur_av; + + for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) { + if (cur_av->node->key.source_type == key->source_type && + cur_av->node->key.target_type == key->target_type && + cur_av->node->key.target_class == key->target_class && + (cur_av->node->key.specified & key->specified)) + + return &cur_av->node->datum; + + } + return NULL; +} + +int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_OK; + avtab_key_t avtab_key; + avtab_datum_t avtab_datum; + avtab_ptr_t existing; + + avtab_key.source_type = src; + avtab_key.target_type = tgt; + avtab_key.target_class = obj; + + switch (kind) { + case CIL_TYPE_TRANSITION: + avtab_key.specified = AVTAB_TRANSITION; + break; + case CIL_TYPE_CHANGE: + avtab_key.specified = AVTAB_CHANGE; + break; + case CIL_TYPE_MEMBER: + avtab_key.specified = AVTAB_MEMBER; + break; + default: + rc = SEPOL_ERR; + goto exit; + } + + avtab_datum.data = res; + + existing = avtab_search_node(&pdb->te_avtab, &avtab_key); + if (existing) { + /* Don't add duplicate type rule and warn if they conflict. + * A warning should have been previously given if there is a + * non-duplicate rule using the same key. + */ + if (existing->datum.data != res) { + cil_log(CIL_ERR, "Conflicting type rules\n"); + rc = SEPOL_ERR; + } + goto exit; + } + + if (!cond_node) { + rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum); + } else { + existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key); + if (existing) { + cond_av_list_t *this_list; + cond_av_list_t *other_list; + avtab_datum_t *search_datum; + + if (cond_flavor == CIL_CONDTRUE) { + this_list = cond_node->true_list; + other_list = cond_node->false_list; + } else { + this_list = cond_node->false_list; + other_list = cond_node->true_list; + } + + search_datum = cil_cond_av_list_search(&avtab_key, other_list); + if (search_datum == NULL) { + if (existing->datum.data != res) { + cil_log(CIL_ERR, "Conflicting type rules\n"); + rc = SEPOL_ERR; + goto exit; + } + + search_datum = cil_cond_av_list_search(&avtab_key, this_list); + if (search_datum) { + goto exit; + } + } + } + rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor); + } + +exit: + return rc; +} + +int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_ERR; + uint16_t kind = cil_rule->rule_kind; + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; + struct cil_list *class_list; + type_datum_t *sepol_result = NULL; + ebitmap_t src_bitmap, tgt_bitmap; + ebitmap_node_t *node1, *node2; + unsigned int i, j; + struct cil_list_item *c; + + rc = __cil_expand_type(cil_rule->src, &src_bitmap); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_expand_type(cil_rule->tgt, &tgt_bitmap); + if (rc != SEPOL_OK) goto exit; + + class_list = cil_expand_class(cil_rule->obj); + + rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_rule->result), &sepol_result); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&src_bitmap, node1, i) { + if (!ebitmap_get_bit(&src_bitmap, i)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&tgt_bitmap, node2, j) { + if (!ebitmap_get_bit(&tgt_bitmap, j)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + cil_list_for_each(c, class_list) { + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_insert_type_rule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, sepol_result->s.value, cond_node, cond_flavor); + if (rc != SEPOL_OK) goto exit; + } + } + } + + rc = SEPOL_OK; + +exit: + ebitmap_destroy(&src_bitmap); + ebitmap_destroy(&tgt_bitmap); + cil_list_destroy(&class_list, CIL_FALSE); + return rc; +} + +int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule) +{ + return __cil_type_rule_to_avtab(pdb, db, cil_rule, NULL, CIL_FALSE); +} + +int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor, hashtab_t filename_trans_table) +{ + int rc = SEPOL_ERR; + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; + struct cil_list *class_list; + type_datum_t *sepol_result = NULL; + filename_trans_t *new = NULL; + ebitmap_t src_bitmap, tgt_bitmap; + ebitmap_node_t *node1, *node2; + unsigned int i, j; + struct cil_list_item *c; + char *name = DATUM(typetrans->name)->name; + uint32_t *otype = NULL; + + if (name == CIL_KEY_STAR) { + struct cil_type_rule trans; + trans.rule_kind = CIL_TYPE_TRANSITION; + trans.src = typetrans->src; + trans.tgt = typetrans->tgt; + trans.obj = typetrans->obj; + trans.result = typetrans->result; + return __cil_type_rule_to_avtab(pdb, db, &trans, cond_node, cond_flavor); + } + + rc = __cil_expand_type(typetrans->src, &src_bitmap); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_expand_type(typetrans->tgt, &tgt_bitmap); + if (rc != SEPOL_OK) goto exit; + + class_list = cil_expand_class(typetrans->obj); + + rc = __cil_get_sepol_type_datum(pdb, DATUM(typetrans->result), &sepol_result); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&src_bitmap, node1, i) { + if (!ebitmap_get_bit(&src_bitmap, i)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&tgt_bitmap, node2, j) { + if (!ebitmap_get_bit(&tgt_bitmap, j)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + cil_list_for_each(c, class_list) { + int add = CIL_TRUE; + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) goto exit; + + new = cil_malloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); + new->stype = sepol_src->s.value; + new->ttype = sepol_tgt->s.value; + new->tclass = sepol_obj->s.value; + new->otype = sepol_result->s.value; + new->name = cil_strdup(name); + + rc = hashtab_insert(filename_trans_table, (hashtab_key_t)new, &(new->otype)); + if (rc != SEPOL_OK) { + if (rc == SEPOL_EEXIST) { + add = CIL_FALSE; + otype = hashtab_search(filename_trans_table, (hashtab_key_t)new); + if (new->otype != *otype) { + cil_log(CIL_ERR, "Conflicting name type transition rules\n"); + } else { + rc = SEPOL_OK; + } + } else { + cil_log(CIL_ERR, "Out of memory\n"); + } + } + + if (add == CIL_TRUE) { + new->next = pdb->filename_trans; + pdb->filename_trans = new; + } else { + free(new->name); + free(new); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + } + } + + rc = SEPOL_OK; + +exit: + ebitmap_destroy(&src_bitmap); + ebitmap_destroy(&tgt_bitmap); + cil_list_destroy(&class_list, CIL_FALSE); + return rc; +} + +int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, hashtab_t filename_trans_table) +{ + return __cil_typetransition_to_avtab(pdb, db, typetrans, NULL, CIL_FALSE, filename_trans_table); +} + +int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum) +{ + int rc; + perm_datum_t *sepol_perm; + common_datum_t *sepol_common; + + sepol_perm = hashtab_search(sepol_class->permissions.table, perm_str); + if (sepol_perm == NULL) { + sepol_common = sepol_class->comdatum; + sepol_perm = hashtab_search(sepol_common->permissions.table, perm_str); + if (sepol_perm == NULL) { + cil_log(CIL_ERR, "Failed to find datum for perm %s\n", perm_str); + rc = SEPOL_ERR; + goto exit; + } + } + *datum |= 1 << (sepol_perm->s.value - 1); + + return SEPOL_OK; + +exit: + return rc; +} + +int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum) +{ + int rc = SEPOL_ERR; + char *key = NULL; + struct cil_list_item *curr_perm; + struct cil_perm *cil_perm; + uint32_t data = 0; + + cil_list_for_each(curr_perm, perms) { + cil_perm = curr_perm->data; + key = cil_perm->datum.fqn; + + rc = __perm_str_to_datum(key, sepol_class, &data); + if (rc != SEPOL_OK) { + goto exit; + } + } + + *datum = data; + + return SEPOL_OK; + +exit: + return rc; +} + +int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_OK; + avtab_key_t avtab_key; + avtab_datum_t avtab_datum; + avtab_datum_t *avtab_dup = NULL; + + avtab_key.source_type = src; + avtab_key.target_type = tgt; + avtab_key.target_class = obj; + + switch (kind) { + case CIL_AVRULE_ALLOWED: + avtab_key.specified = AVTAB_ALLOWED; + break; + case CIL_AVRULE_AUDITALLOW: + avtab_key.specified = AVTAB_AUDITALLOW; + break; + case CIL_AVRULE_DONTAUDIT: + avtab_key.specified = AVTAB_AUDITDENY; + break; + default: + rc = SEPOL_ERR; + goto exit; + break; + } + + if (!cond_node) { + avtab_dup = avtab_search(&pdb->te_avtab, &avtab_key); + if (!avtab_dup) { + avtab_datum.data = data; + rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum); + } else { + if (kind == CIL_AVRULE_DONTAUDIT) + avtab_dup->data &= data; + else + avtab_dup->data |= data; + } + } else { + avtab_datum.data = data; + rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor); + } + +exit: + return rc; +} + +int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_ERR; + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_class = NULL; + uint32_t data = 0; + + rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_perms_to_datum(cp->perms, sepol_class, &data); + if (rc != SEPOL_OK) goto exit; + + if (data == 0) { + /* No permissions, so don't insert rule. Maybe should return an error? */ + return SEPOL_OK; + } + + if (kind == CIL_AVRULE_DONTAUDIT) { + data = ~data; + } + + rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_insert_avrule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_class->s.value, data, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + goto exit; + } + + return SEPOL_OK; + +exit: + return rc; +} + + +int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_ERR; + struct cil_list_item *curr; + + cil_list_for_each(curr, classperms) { + if (curr->flavor == CIL_CLASSPERMS) { + struct cil_classperms *cp = curr->data; + if (FLAVOR(cp->class) == CIL_CLASS) { + rc = __cil_avrule_expand_helper(pdb, kind, src, tgt, cp, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + goto exit; + } + } else { /* MAP */ + struct cil_list_item *i = NULL; + cil_list_for_each(i, cp->perms) { + struct cil_perm *cmp = i->data; + rc = __cil_avrule_expand(pdb, kind, src, tgt, cmp->classperms, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + } else { /* SET */ + struct cil_classperms_set *cp_set = curr->data; + struct cil_classpermission *cp = cp_set->set; + rc = __cil_avrule_expand(pdb, kind, src, tgt, cp->classperms, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor) +{ + int rc = SEPOL_ERR; + uint16_t kind = cil_avrule->rule_kind; + struct cil_symtab_datum *src = NULL; + struct cil_symtab_datum *tgt = NULL; + struct cil_list *classperms = cil_avrule->perms.classperms; + + if (cil_avrule->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) { + // Do not add dontaudit rules to binary + rc = SEPOL_OK; + goto exit; + } + + src = cil_avrule->src; + tgt = cil_avrule->tgt; + + if (tgt->fqn == CIL_KEY_SELF) { + ebitmap_t type_bitmap; + ebitmap_node_t *tnode; + unsigned int i; + + rc = __cil_expand_type(src, &type_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&type_bitmap, tnode, i) { + if (!ebitmap_get_bit(&type_bitmap, i)) continue; + + src = DATUM(db->val_to_type[i]); + rc = __cil_avrule_expand(pdb, kind, src, src, classperms, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + ebitmap_destroy(&type_bitmap); + goto exit; + } + } + ebitmap_destroy(&type_bitmap); + } else { + rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor); + if (rc != SEPOL_OK) goto exit; + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule) +{ + return __cil_avrule_to_avtab(pdb, db, cil_avrule, NULL, CIL_FALSE); +} + +// Copied from checkpolicy/policy_define.c + +/* index of the u32 containing the permission */ +#define XPERM_IDX(x) (x >> 5) +/* set bits 0 through x-1 within the u32 */ +#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1) +/* low value for this u32 */ +#define XPERM_LOW(x) (x << 5) +/* high value for this u32 */ +#define XPERM_HIGH(x) (((x + 1) << 5) - 1) +void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_extended_perms *xperms) +{ + unsigned int i; + uint16_t h = high + 1; + /* for each u32 that this low-high range touches, set driver permissions */ + for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) { + /* set all bits in u32 */ + if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) + xperms->perms[i] |= ~0U; + /* set low bits */ + else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i))) + xperms->perms[i] |= XPERM_SETBITS(h); + /* set high bits */ + else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) + xperms->perms[i] |= ~0U - XPERM_SETBITS(low); + /* set middle bits */ + else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i))) + xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low); + } +} + + +#define IOC_DRIV(x) (x >> 8) +#define IOC_FUNC(x) (x & 0xff) + +int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) +{ + ebitmap_node_t *node; + unsigned int i; + uint16_t low = 0, high = 0; + struct avtab_extended_perms *partial = NULL; + struct avtab_extended_perms *complete = NULL; + int start_new_range; + + cil_list_init(xperms_list, CIL_NONE); + + start_new_range = 1; + + ebitmap_for_each_bit(xperms, node, i) { + if (!ebitmap_get_bit(xperms, i)) continue; + + if (start_new_range) { + low = i; + start_new_range = 0; + } + + // continue if the current bit isn't the end of the driver function or the next bit is set + if (IOC_FUNC(i) != 0xff && ebitmap_get_bit(xperms, i + 1)) { + continue; + } + + // if we got here, i is the end of this range (either becuase the func + // is 0xff or the next bit isn't set). The next time around we are + // going to need a start a new range + high = i; + start_new_range = 1; + + if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { + if (!complete) { + complete = cil_calloc(1, sizeof(*complete)); + complete->driver = 0x0; + complete->specified = AVTAB_XPERMS_IOCTLDRIVER; + } + + __avrule_xperm_setrangebits(IOC_DRIV(low), IOC_DRIV(low), complete); + } else { + if (partial && partial->driver != IOC_DRIV(low)) { + cil_list_append(*xperms_list, CIL_NONE, partial); + partial = NULL; + } + + if (!partial) { + partial = cil_calloc(1, sizeof(*partial)); + partial->driver = IOC_DRIV(low); + partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; + } + + __avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial); + } + } + + if (partial) { + cil_list_append(*xperms_list, CIL_NONE, partial); + } + + if (complete) { + cil_list_append(*xperms_list, CIL_NONE, complete); + } + + return SEPOL_OK; +} + +int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) +{ + int rc = SEPOL_OK; + struct policydb *pdb; + avtab_key_t *avtab_key; + avtab_datum_t avtab_datum; + struct cil_list *xperms_list = NULL; + struct cil_list_item *item; + class_datum_t *sepol_obj; + uint32_t data = 0; + + avtab_key = (avtab_key_t *)k; + pdb = args; + + sepol_obj = pdb->class_val_to_struct[avtab_key->target_class - 1]; + + // setting the data for an extended avtab isn't really neccessary because + // it is ignored by the kernel. However, neverallow checking requires that + // the data value be set, so set it for that to work. + rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data); + if (rc != SEPOL_OK) { + goto exit; + } + avtab_datum.data = data; + + rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list); + if (rc != SEPOL_OK) { + goto exit; + } + + cil_list_for_each(item, xperms_list) { + avtab_datum.xperms = item->data; + rc = avtab_insert(&pdb->te_avtab, avtab_key, &avtab_datum); + if (rc != SEPOL_OK) { + goto exit; + } + } + + rc = SEPOL_OK; + +exit: + if (xperms_list != NULL) { + cil_list_for_each(item, xperms_list) { + free(item->data); + } + cil_list_destroy(&xperms_list, CIL_FALSE); + } + + // hashtab_t does not have a way to free keys or datum since it doesn't + // know what they are. We won't need the keys/datum after this function, so + // clean them up here. + free(avtab_key); + ebitmap_destroy(datum); + free(datum); + + return rc; +} + +int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) +{ + uint16_t specified; + avtab_key_t *avtab_key; + ebitmap_t *hashtab_xperms; + int rc = SEPOL_ERR; + + switch (kind) { + case CIL_AVRULE_ALLOWED: + specified = AVTAB_XPERMS_ALLOWED; + break; + case CIL_AVRULE_AUDITALLOW: + specified = AVTAB_XPERMS_AUDITALLOW; + break; + case CIL_AVRULE_DONTAUDIT: + specified = AVTAB_XPERMS_DONTAUDIT; + break; + default: + rc = SEPOL_ERR; + goto exit; + } + + avtab_key = cil_malloc(sizeof(*avtab_key)); + avtab_key->source_type = src; + avtab_key->target_type = tgt; + avtab_key->target_class = obj; + avtab_key->specified = specified; + + hashtab_xperms = (ebitmap_t *)hashtab_search(h, (hashtab_key_t)avtab_key); + if (!hashtab_xperms) { + hashtab_xperms = cil_malloc(sizeof(*hashtab_xperms)); + rc = ebitmap_cpy(hashtab_xperms, xperms); + if (rc != SEPOL_OK) { + free(avtab_key); + goto exit; + } + rc = hashtab_insert(h, (hashtab_key_t)avtab_key, hashtab_xperms); + if (rc != SEPOL_OK) { + free(avtab_key); + goto exit; + } + } else { + free(avtab_key); + rc = ebitmap_union(hashtab_xperms, xperms); + if (rc != SEPOL_OK) { + goto exit; + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args) +{ + int rc = SEPOL_ERR; + type_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; + struct cil_list *class_list = NULL; + struct cil_list_item *c; + + rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + class_list = cil_expand_class(permx->obj); + + cil_list_for_each(c, class_list) { + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) goto exit; + + switch (permx->kind) { + case CIL_PERMX_KIND_IOCTL: + rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); + if (rc != SEPOL_OK) goto exit; + break; + default: + rc = SEPOL_ERR; + goto exit; + } + } + + rc = SEPOL_OK; + +exit: + cil_list_destroy(&class_list, CIL_FALSE); + + return rc; +} + +int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args) +{ + int rc = SEPOL_ERR; + uint16_t kind; + struct cil_symtab_datum *src = NULL; + struct cil_symtab_datum *tgt = NULL; + ebitmap_t type_bitmap; + ebitmap_node_t *tnode; + unsigned int i; + + ebitmap_init(&type_bitmap); + + if (cil_avrulex->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) { + // Do not add dontaudit rules to binary + rc = SEPOL_OK; + goto exit; + } + + kind = cil_avrulex->rule_kind; + src = cil_avrulex->src; + tgt = cil_avrulex->tgt; + + if (tgt->fqn == CIL_KEY_SELF) { + rc = __cil_expand_type(src, &type_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&type_bitmap, tnode, i) { + if (!ebitmap_get_bit(&type_bitmap, i)) continue; + + src = DATUM(db->val_to_type[i]); + rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, src, cil_avrulex->perms.x.permx, args); + if (rc != SEPOL_OK) { + goto exit; + } + } + } else { + rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args); + if (rc != SEPOL_OK) goto exit; + } + + rc = SEPOL_OK; + +exit: + ebitmap_destroy(&type_bitmap); + + return rc; +} + +int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) +{ + int rc; + enum cil_flavor flavor; + struct cil_args_booleanif *args = extra_args; + const struct cil_db *db = args->db; + policydb_t *pdb = args->pdb; + cond_node_t *cond_node = args->cond_node; + enum cil_flavor cond_flavor = args->cond_flavor; + struct cil_type_rule *cil_type_rule; + struct cil_avrule *cil_avrule; + struct cil_nametypetransition *cil_typetrans; + hashtab_t filename_trans_table = args->filename_trans_table; + + flavor = node->flavor; + switch (flavor) { + case CIL_NAMETYPETRANSITION: + cil_typetrans = (struct cil_nametypetransition*)node->data; + if (DATUM(cil_typetrans->name)->fqn != CIL_KEY_STAR) { + cil_log(CIL_ERR, "typetransition with file name not allowed within a booleanif block.\n"); + cil_tree_log(node, CIL_ERR,"Invalid typetransition statement"); + goto exit; + } + rc = __cil_typetransition_to_avtab(pdb, db, cil_typetrans, cond_node, cond_flavor, filename_trans_table); + if (rc != SEPOL_OK) { + cil_tree_log(node, CIL_ERR, "Failed to insert type transition into avtab"); + goto exit; + } + break; + case CIL_TYPE_RULE: + cil_type_rule = node->data; + rc = __cil_type_rule_to_avtab(pdb, db, cil_type_rule, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + cil_tree_log(node, CIL_ERR, "Failed to insert typerule into avtab"); + goto exit; + } + break; + case CIL_AVRULE: + cil_avrule = node->data; + rc = __cil_avrule_to_avtab(pdb, db, cil_avrule, cond_node, cond_flavor); + if (rc != SEPOL_OK) { + cil_tree_log(node, CIL_ERR, "Failed to insert avrule into avtab"); + goto exit; + } + break; + case CIL_CALL: + case CIL_TUNABLEIF: + break; + default: + cil_tree_log(node, CIL_ERR, "Invalid statement within booleanif"); + goto exit; + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out); + +static void __cil_expr_to_string_helper(struct cil_list_item *curr, enum cil_flavor flavor, char **out) +{ + char *c; + + if (curr->flavor == CIL_DATUM) { + *out = cil_strdup(DATUM(curr->data)->fqn); + } else if (curr->flavor == CIL_LIST) { + __cil_expr_to_string(curr->data, flavor, &c); + cil_asprintf(out, "(%s)", c); + free(c); + } else if (flavor == CIL_PERMISSIONX) { + // permissionx expressions aren't resolved into anything, so curr->flavor + // is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those + *out = cil_strdup(curr->data); + } +} + +static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out) +{ + struct cil_list_item *curr; + char *s1 = NULL; + char *s2 = NULL; + enum cil_flavor op; + + if (expr == NULL || expr->head == NULL) { + *out = cil_strdup(""); + return; + } + + curr = expr->head; + + if (curr->flavor == CIL_OP) { + op = (enum cil_flavor)curr->data; + + if (op == CIL_ALL) { + *out = cil_strdup(CIL_KEY_ALL); + } else if (op == CIL_RANGE) { + __cil_expr_to_string_helper(curr->next, flavor, &s1); + __cil_expr_to_string_helper(curr->next->next, flavor, &s2); + cil_asprintf(out, "%s %s %s", CIL_KEY_RANGE, s1, s2); + free(s1); + free(s2); + } else { + __cil_expr_to_string_helper(curr->next, flavor, &s1); + + if (op == CIL_NOT) { + cil_asprintf(out, "%s %s", CIL_KEY_NOT, s1); + free(s1); + } else { + char *opstr = ""; + + __cil_expr_to_string_helper(curr->next->next, flavor, &s2); + + if (op == CIL_OR) { + opstr = CIL_KEY_OR; + } else if (op == CIL_AND) { + opstr = CIL_KEY_AND; + } else if (op == CIL_XOR) { + opstr = CIL_KEY_XOR; + } + + cil_asprintf(out, "%s %s %s", opstr, s1, s2); + free(s1); + free(s2); + } + } + } else { + char *c1 = NULL; + char *c2 = NULL; + __cil_expr_to_string_helper(curr, flavor, &c1); + for (curr = curr->next; curr; curr = curr->next) { + __cil_expr_to_string_helper(curr, flavor, &s1); + cil_asprintf(&c2, "%s %s", c1, s1); + free(c1); + free(s1); + c1 = c2; + } + *out = c1; + } +} + +static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail); + +static int __cil_cond_item_to_sepol_expr(policydb_t *pdb, struct cil_list_item *item, cond_expr_t **head, cond_expr_t **tail) +{ + if (item == NULL) { + goto exit; + } else if (item->flavor == CIL_DATUM) { + char *key = DATUM(item->data)->fqn; + cond_bool_datum_t *sepol_bool = hashtab_search(pdb->p_bools.table, key); + if (sepol_bool == NULL) { + cil_log(CIL_INFO, "Failed to find boolean\n"); + goto exit; + } + *head = cil_malloc(sizeof(cond_expr_t)); + (*head)->next = NULL; + (*head)->expr_type = COND_BOOL; + (*head)->bool = sepol_bool->s.value; + *tail = *head; + } else if (item->flavor == CIL_LIST) { + struct cil_list *l = item->data; + int rc = __cil_cond_expr_to_sepol_expr_helper(pdb, l, head, tail); + if (rc != SEPOL_OK) { + goto exit; + } + } else { + goto exit; + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail) +{ + int rc = SEPOL_ERR; + struct cil_list_item *item = cil_expr->head; + enum cil_flavor flavor = cil_expr->flavor; + cond_expr_t *op, *h1, *h2, *t1, *t2; + + if (flavor != CIL_BOOL) { + cil_log(CIL_INFO, "Expected boolean expression\n"); + goto exit; + } + + if (item == NULL) { + goto exit; + } else if (item->flavor == CIL_OP) { + enum cil_flavor cil_op = (enum cil_flavor)item->data; + + op = cil_malloc(sizeof(*op)); + op->bool = 0; + op->next = NULL; + + switch (cil_op) { + case CIL_NOT: + op->expr_type = COND_NOT; + break; + case CIL_OR: + op->expr_type = COND_OR; + break; + case CIL_AND: + op->expr_type = COND_AND; + break; + case CIL_XOR: + op->expr_type = COND_XOR; + break; + case CIL_EQ: + op->expr_type = COND_EQ; + break; + case CIL_NEQ: + op->expr_type = COND_NEQ; + break; + default: + goto exit; + } + + rc = __cil_cond_item_to_sepol_expr(pdb, item->next, &h1, &t1); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to get first operand of conditional expression\n"); + free(op); + goto exit; + } + + if (cil_op == CIL_NOT) { + *head = h1; + t1->next = op; + *tail = op; + } else { + rc = __cil_cond_item_to_sepol_expr(pdb, item->next->next, &h2, &t2); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to get second operand of conditional expression\n"); + free(op); + cond_expr_destroy(h1); + goto exit; + } + + *head = h1; + t1->next = h2; + t2->next = op; + *tail = op; + } + } else { + rc = __cil_cond_item_to_sepol_expr(pdb, item, &h1, &t1); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to get initial item in conditional list\n"); + goto exit; + } + *head = h1; + for (item = item->next; item; item = item->next) { + rc = __cil_cond_item_to_sepol_expr(pdb, item, &h2, &t2); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failed to get item in conditional list\n"); + cond_expr_destroy(*head); + goto exit; + } + op = cil_malloc(sizeof(*op)); + op->bool = 0; + op->next = NULL; + op->expr_type = COND_OR; + t1->next = h2; + t2->next = op; + t1 = op; + } + *tail = t1; + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +static int __cil_cond_expr_to_sepol_expr(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **sepol_expr) +{ + int rc; + cond_expr_t *head, *tail; + + rc = __cil_cond_expr_to_sepol_expr_helper(pdb, cil_expr, &head, &tail); + if (rc != SEPOL_OK) { + return SEPOL_ERR; + } + *sepol_expr = head; + + return SEPOL_OK; +} + +int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table) +{ + int rc = SEPOL_ERR; + struct cil_args_booleanif bool_args; + struct cil_booleanif *cil_boolif = (struct cil_booleanif*)node->data; + struct cil_tree_node *cb_node = node->cl_head; + struct cil_tree_node *true_node = NULL; + struct cil_tree_node *false_node = NULL; + struct cil_tree_node *tmp_node = NULL; + cond_node_t *tmp_cond = NULL; + cond_node_t *cond_node = NULL; + int was_created; + int swapped = CIL_FALSE; + cond_av_list_t tmp_cl; + + tmp_cond = cond_node_create(pdb, NULL); + if (tmp_cond == NULL) { + rc = SEPOL_ERR; + cil_tree_log(node, CIL_INFO, "Failed to create sepol conditional node"); + goto exit; + } + + rc = __cil_cond_expr_to_sepol_expr(pdb, cil_boolif->datum_expr, &tmp_cond->expr); + if (rc != SEPOL_OK) { + cil_tree_log(node, CIL_INFO, "Failed to convert CIL conditional expression to sepol expression"); + goto exit; + } + + tmp_cond->true_list = &tmp_cl; + + rc = cond_normalize_expr(pdb, tmp_cond); + if (rc != SEPOL_OK) { + goto exit; + } + + if (tmp_cond->false_list != NULL) { + tmp_cond->true_list = NULL; + swapped = CIL_TRUE; + } + + cond_node = cond_node_find(pdb, tmp_cond, pdb->cond_list, &was_created); + if (cond_node == NULL) { + rc = SEPOL_ERR; + goto exit; + } + + if (was_created) { + cond_node->next = pdb->cond_list; + pdb->cond_list = cond_node; + } + + cond_expr_destroy(tmp_cond->expr); + free(tmp_cond); + + for (cb_node = node->cl_head; cb_node != NULL; cb_node = cb_node->next) { + if (cb_node->flavor == CIL_CONDBLOCK) { + struct cil_condblock *cb = cb_node->data; + if (cb->flavor == CIL_CONDTRUE) { + true_node = cb_node; + } else if (cb->flavor == CIL_CONDFALSE) { + false_node = cb_node; + } + } + } + + if (swapped) { + tmp_node = true_node; + true_node = false_node; + false_node = tmp_node; + } + + bool_args.db = db; + bool_args.pdb = pdb; + bool_args.cond_node = cond_node; + bool_args.filename_trans_table = filename_trans_table; + + if (true_node != NULL) { + bool_args.cond_flavor = CIL_CONDTRUE; + rc = cil_tree_walk(true_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); + if (rc != SEPOL_OK) { + cil_tree_log(true_node, CIL_ERR, "Failure while walking true conditional block"); + goto exit; + } + } + + if (false_node != NULL) { + bool_args.cond_flavor = CIL_CONDFALSE; + rc = cil_tree_walk(false_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); + if (rc != SEPOL_OK) { + cil_tree_log(false_node, CIL_ERR, "Failure while walking false conditional block"); + goto exit; + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table) +{ + int rc = SEPOL_ERR; + role_datum_t *sepol_src = NULL; + type_datum_t *sepol_tgt = NULL; + class_datum_t *sepol_obj = NULL; + struct cil_list *class_list; + role_datum_t *sepol_result = NULL; + role_trans_t *new = NULL; + uint32_t *new_role = NULL; + ebitmap_t role_bitmap, type_bitmap; + ebitmap_node_t *rnode, *tnode; + unsigned int i, j; + struct cil_list_item *c; + + rc = __cil_expand_role(DATUM(roletrans->src), &role_bitmap); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_expand_type(roletrans->tgt, &type_bitmap); + if (rc != SEPOL_OK) goto exit; + + class_list = cil_expand_class(roletrans->obj); + + rc = __cil_get_sepol_role_datum(pdb, DATUM(roletrans->result), &sepol_result); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&role_bitmap, rnode, i) { + if (!ebitmap_get_bit(&role_bitmap, i)) continue; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&type_bitmap, tnode, j) { + if (!ebitmap_get_bit(&type_bitmap, j)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + cil_list_for_each(c, class_list) { + int add = CIL_TRUE; + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); + if (rc != SEPOL_OK) goto exit; + + new = cil_malloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); + new->role = sepol_src->s.value; + new->type = sepol_tgt->s.value; + new->tclass = sepol_obj->s.value; + new->new_role = sepol_result->s.value; + + rc = SEPOL_OK; + rc = hashtab_insert(role_trans_table, (hashtab_key_t)new, &(new->new_role)); + if (rc != SEPOL_OK) { + if (rc == SEPOL_EEXIST) { + add = CIL_FALSE; + new_role = hashtab_search(role_trans_table, (hashtab_key_t)new); + if (new->new_role != *new_role) { + cil_log(CIL_ERR, "Conflicting role transition rules\n"); + } else { + rc = SEPOL_OK; + } + } else { + cil_log(CIL_ERR, "Out of memory\n"); + } + } + + if (add == CIL_TRUE) { + new->next = pdb->role_tr; + pdb->role_tr = new; + } else { + free(new); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + } + } + + rc = SEPOL_OK; + +exit: + ebitmap_destroy(&role_bitmap); + ebitmap_destroy(&type_bitmap); + cil_list_destroy(&class_list, CIL_FALSE); + return rc; +} + +int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow) +{ + int rc = SEPOL_ERR; + role_datum_t *sepol_src = NULL; + role_datum_t *sepol_tgt = NULL; + role_allow_t *sepol_roleallow = NULL; + ebitmap_t src_bitmap, tgt_bitmap; + ebitmap_node_t *node1, *node2; + unsigned int i, j; + + rc = __cil_expand_role(roleallow->src, &src_bitmap); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_expand_role(roleallow->tgt, &tgt_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&src_bitmap, node1, i) { + if (!ebitmap_get_bit(&src_bitmap, i)) continue; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&tgt_bitmap, node2, j) { + if (!ebitmap_get_bit(&tgt_bitmap, j)) continue; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[j]), &sepol_tgt); + if (rc != SEPOL_OK) goto exit; + + sepol_roleallow = cil_malloc(sizeof(*sepol_roleallow)); + memset(sepol_roleallow, 0, sizeof(role_allow_t)); + sepol_roleallow->role = sepol_src->s.value; + sepol_roleallow->new_role = sepol_tgt->s.value; + + sepol_roleallow->next = pdb->role_allow; + pdb->role_allow = sepol_roleallow; + } + } + + rc = SEPOL_OK; + +exit: + ebitmap_destroy(&src_bitmap); + ebitmap_destroy(&tgt_bitmap); + return rc; +} + +int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr) +{ + int rc = SEPOL_ERR; + + if (expr_flavor == CIL_USER) { + user_datum_t *sepol_user = NULL; + ebitmap_t user_bitmap; + ebitmap_node_t *unode; + unsigned int i; + + rc = __cil_expand_user(item->data, &user_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&user_bitmap, unode, i) { + if (!ebitmap_get_bit(&user_bitmap, i)) { + continue; + } + + rc = __cil_get_sepol_user_datum(pdb, DATUM(db->val_to_user[i]), &sepol_user); + if (rc != SEPOL_OK) { + ebitmap_destroy(&user_bitmap); + goto exit; + } + + if (ebitmap_set_bit(&expr->names, sepol_user->s.value - 1, 1)) { + ebitmap_destroy(&user_bitmap); + goto exit; + } + } + ebitmap_destroy(&user_bitmap); + } else if (expr_flavor == CIL_ROLE) { + role_datum_t *sepol_role = NULL; + ebitmap_t role_bitmap; + ebitmap_node_t *rnode; + unsigned int i; + + rc = __cil_expand_role(item->data, &role_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&role_bitmap, rnode, i) { + if (!ebitmap_get_bit(&role_bitmap, i)) continue; + + rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role); + if (rc != SEPOL_OK) { + ebitmap_destroy(&role_bitmap); + goto exit; + } + + if (ebitmap_set_bit(&expr->names, sepol_role->s.value - 1, 1)) { + ebitmap_destroy(&role_bitmap); + goto exit; + } + } + ebitmap_destroy(&role_bitmap); + } else if (expr_flavor == CIL_TYPE) { + type_datum_t *sepol_type = NULL; + ebitmap_t type_bitmap; + ebitmap_node_t *tnode; + unsigned int i; + + if (pdb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) { + rc = __cil_get_sepol_type_datum(pdb, item->data, &sepol_type); + if (rc != SEPOL_OK) { + ebitmap_destroy(&type_bitmap); + goto exit; + } + + if (ebitmap_set_bit(&expr->type_names->types, sepol_type->s.value - 1, 1)) { + ebitmap_destroy(&type_bitmap); + goto exit; + } + } + + rc = __cil_expand_type(item->data, &type_bitmap); + if (rc != SEPOL_OK) goto exit; + + ebitmap_for_each_bit(&type_bitmap, tnode, i) { + if (!ebitmap_get_bit(&type_bitmap, i)) continue; + + rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); + if (rc != SEPOL_OK) { + ebitmap_destroy(&type_bitmap); + goto exit; + } + + if (ebitmap_set_bit(&expr->names, sepol_type->s.value - 1, 1)) { + ebitmap_destroy(&type_bitmap); + goto exit; + } + } + ebitmap_destroy(&type_bitmap); + } else { + goto exit; + } + + return SEPOL_OK; + +exit: + return SEPOL_ERR; +} + +int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr) +{ + int rc = SEPOL_ERR; + struct cil_list_item *l_item = op_item->next; + struct cil_list_item *r_item = op_item->next->next; + + enum cil_flavor l_operand = (enum cil_flavor)l_item->data; + + switch (l_operand) { + case CIL_CONS_U1: + expr->attr = CEXPR_USER; + break; + case CIL_CONS_U2: + expr->attr = CEXPR_USER | CEXPR_TARGET; + break; + case CIL_CONS_U3: + expr->attr = CEXPR_USER | CEXPR_XTARGET; + break; + case CIL_CONS_R1: + expr->attr = CEXPR_ROLE; + break; + case CIL_CONS_R2: + expr->attr = CEXPR_ROLE | CEXPR_TARGET; + break; + case CIL_CONS_R3: + expr->attr = CEXPR_ROLE | CEXPR_XTARGET; + break; + case CIL_CONS_T1: + expr->attr = CEXPR_TYPE; + break; + case CIL_CONS_T2: + expr->attr = CEXPR_TYPE | CEXPR_TARGET; + break; + case CIL_CONS_T3: + expr->attr = CEXPR_TYPE | CEXPR_XTARGET; + break; + case CIL_CONS_L1: { + enum cil_flavor r_operand = (enum cil_flavor)r_item->data; + + if (r_operand == CIL_CONS_L2) { + expr->attr = CEXPR_L1L2; + } else if (r_operand == CIL_CONS_H1) { + expr->attr = CEXPR_L1H1; + } else { + expr->attr = CEXPR_L1H2; + } + break; + } + case CIL_CONS_L2: + expr->attr = CEXPR_L2H2; + break; + case CIL_CONS_H1: { + enum cil_flavor r_operand = (enum cil_flavor)r_item->data; + if (r_operand == CIL_CONS_L2) { + expr->attr = CEXPR_H1L2; + } else { + expr->attr = CEXPR_H1H2; + } + break; + } + default: + goto exit; + break; + } + + if (r_item->flavor == CIL_CONS_OPERAND) { + expr->expr_type = CEXPR_ATTR; + } else { + expr->expr_type = CEXPR_NAMES; + if (r_item->flavor == CIL_DATUM) { + rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, r_item, expr_flavor, expr); + if (rc != SEPOL_OK) { + goto exit; + } + } else if (r_item->flavor == CIL_LIST) { + struct cil_list *r_expr = r_item->data; + struct cil_list_item *curr; + cil_list_for_each(curr, r_expr) { + rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, curr, expr_flavor, expr); + if (rc != SEPOL_OK) { + goto exit; + } + } + } else { + rc = SEPOL_ERR; + goto exit; + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail) +{ + int rc = SEPOL_ERR; + struct cil_list_item *item; + enum cil_flavor flavor; + constraint_expr_t *op, *h1, *h2, *t1, *t2; + int is_leaf = CIL_FALSE; + + if (cil_expr == NULL) { + return SEPOL_ERR; + } + + item = cil_expr->head; + flavor = cil_expr->flavor; + + op = cil_malloc(sizeof(constraint_expr_t)); + rc = constraint_expr_init(op); + if (rc != SEPOL_OK) { + goto exit; + } + + enum cil_flavor cil_op = (enum cil_flavor)item->data; + switch (cil_op) { + case CIL_NOT: + op->expr_type = CEXPR_NOT; + break; + case CIL_AND: + op->expr_type = CEXPR_AND; + break; + case CIL_OR: + op->expr_type = CEXPR_OR; + break; + case CIL_EQ: + op->op = CEXPR_EQ; + is_leaf = CIL_TRUE; + break; + case CIL_NEQ: + op->op = CEXPR_NEQ; + is_leaf = CIL_TRUE; + break; + case CIL_CONS_DOM: + op->op = CEXPR_DOM; + is_leaf = CIL_TRUE; + break; + case CIL_CONS_DOMBY: + op->op = CEXPR_DOMBY; + is_leaf = CIL_TRUE; + break; + case CIL_CONS_INCOMP: + op->op = CEXPR_INCOMP; + is_leaf = CIL_TRUE; + break; + default: + goto exit; + } + + if (is_leaf == CIL_TRUE) { + rc = __cil_constrain_expr_leaf_to_sepol_expr(pdb, db, item, flavor, op); + if (rc != SEPOL_OK) { + goto exit; + } + *head = op; + *tail = op; + } else if (cil_op == CIL_NOT) { + struct cil_list *l_expr = item->next->data; + rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1); + if (rc != SEPOL_OK) { + goto exit; + } + t1->next = op; + *head = h1; + *tail = op; + } else { + struct cil_list *l_expr = item->next->data; + struct cil_list *r_expr = item->next->next->data; + rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1); + if (rc != SEPOL_OK) { + goto exit; + } + rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, r_expr, &h2, &t2); + if (rc != SEPOL_OK) { + constraint_expr_destroy(h1); + goto exit; + } + t1->next = h2; + t2->next = op; + *head = h1; + *tail = op; + } + + return SEPOL_OK; + +exit: + constraint_expr_destroy(op); + return SEPOL_ERR; +} + +int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr) +{ + int rc; + constraint_expr_t *head, *tail; + + rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, cil_expr, &head, &tail); + if (rc != SEPOL_OK) { + return SEPOL_ERR; + } + + *sepol_expr = head; + + return SEPOL_OK; +} + +int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr) +{ + int rc = SEPOL_ERR; + constraint_node_t *sepol_constrain = NULL; + constraint_expr_t *sepol_expr = NULL; + class_datum_t *sepol_class = NULL; + + sepol_constrain = cil_malloc(sizeof(*sepol_constrain)); + memset(sepol_constrain, 0, sizeof(constraint_node_t)); + + rc = __cil_get_sepol_class_datum(pdb, class, &sepol_class); + if (rc != SEPOL_OK) goto exit; + + rc = __cil_perms_to_datum(perms, sepol_class, &sepol_constrain->permissions); + if (rc != SEPOL_OK) { + goto exit; + } + + rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr); + if (rc != SEPOL_OK) { + goto exit; + } + + sepol_constrain->expr = sepol_expr; + sepol_constrain->next = sepol_class->constraints; + sepol_class->constraints = sepol_constrain; + + return SEPOL_OK; + +exit: + free(sepol_constrain); + return rc; +} + +int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr) +{ + int rc = SEPOL_ERR; + struct cil_list_item *curr; + + cil_list_for_each(curr, classperms) { + if (curr->flavor == CIL_CLASSPERMS) { + struct cil_classperms *cp = curr->data; + if (FLAVOR(cp->class) == CIL_CLASS) { + rc = cil_constrain_to_policydb_helper(pdb, db, DATUM(cp->class), cp->perms, expr); + if (rc != SEPOL_OK) { + goto exit; + } + } else { /* MAP */ + struct cil_list_item *i = NULL; + cil_list_for_each(i, cp->perms) { + struct cil_perm *cmp = i->data; + rc = cil_constrain_expand(pdb, db, cmp->classperms, expr); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + } else { /* SET */ + struct cil_classperms_set *cp_set = curr->data; + struct cil_classpermission *cp = cp_set->set; + rc = cil_constrain_expand(pdb, db, cp->classperms, expr); + if (rc != SEPOL_OK) { + goto exit; + } + } + } + + return SEPOL_OK; + +exit: + return rc; +} + +int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain) +{ + int rc = SEPOL_ERR; + rc = cil_constrain_expand(pdb, db, cil_constrain->classperms, cil_constrain->datum_expr); + if (rc != SEPOL_OK) { + goto exit; + } + + return SEPOL_OK; + +exit: + cil_log(CIL_ERR, "Failed to insert constraint into policydb\n"); + return rc; +} + +int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans) +{ + int rc = SEPOL_ERR; + struct cil_list *expr = cil_validatetrans->datum_expr; + class_datum_t *sepol_class = NULL; + struct cil_list *class_list; + constraint_node_t *sepol_validatetrans = NULL; + constraint_expr_t *sepol_expr = NULL; + struct cil_list_item *c; + + class_list = cil_expand_class(cil_validatetrans->class); + + cil_list_for_each(c, class_list) { + rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); + if (rc != SEPOL_OK) goto exi