diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21e31c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +src/conf-parse.c +src/conf-parse.h +src/conf-scan.c diff --git a/.packit.yaml b/.packit.yaml new file mode 100644 index 0000000..211c29b --- /dev/null +++ b/.packit.yaml @@ -0,0 +1,11 @@ +jobs: +- job: copr_build + metadata: + targets: &id001 [centos-stream-x86_64] + trigger: pull_request +- job: tests + metadata: + targets: *id001 + trigger: pull_request +specfile_path: SPECS/libsemanage.spec +upstream_ref: c8-source-git diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..8add30a --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..390176f --- /dev/null +++ b/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/SPECS/0001-libsemanage-Fix-RESOURCE_LEAK-and-USE_AFTER_FREE-cov.patch b/SPECS/0001-libsemanage-Fix-RESOURCE_LEAK-and-USE_AFTER_FREE-cov.patch new file mode 100644 index 0000000..06e9c8e --- /dev/null +++ b/SPECS/0001-libsemanage-Fix-RESOURCE_LEAK-and-USE_AFTER_FREE-cov.patch @@ -0,0 +1,66 @@ +From dc105dcb5e34e256bcbcf547fea590cfcee06933 Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Wed, 7 Nov 2018 18:17:34 +0100 +Subject: [PATCH] libsemanage: Fix RESOURCE_LEAK and USE_AFTER_FREE coverity + scan defects + +--- + libsemanage/src/direct_api.c | 21 ++++++++------------- + 1 file changed, 8 insertions(+), 13 deletions(-) + +diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c +index c58961be..8e4d116d 100644 +--- a/libsemanage/src/direct_api.c ++++ b/libsemanage/src/direct_api.c +@@ -1028,7 +1028,7 @@ static int semanage_direct_write_langext(semanage_handle_t *sh, + + fp = NULL; + +- ret = 0; ++ return 0; + + cleanup: + if (fp != NULL) fclose(fp); +@@ -2177,7 +2177,6 @@ cleanup: + semanage_module_info_destroy(sh, modinfo); + free(modinfo); + +- if (fp != NULL) fclose(fp); + return status; + } + +@@ -2342,16 +2341,6 @@ static int semanage_direct_get_module_info(semanage_handle_t *sh, + 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, +@@ -2395,7 +2384,13 @@ cleanup: + free(modinfos); + } + +- if (fp != NULL) fclose(fp); ++ if (fp != NULL && fclose(fp) != 0) { ++ ERR(sh, ++ "Unable to close %s module lang ext file.", ++ (*modinfo)->name); ++ status = -1; ++ } ++ + return status; + } + +-- +2.21.0 + diff --git a/SPECS/0002-libsemanage-Add-support-for-DCCP-and-SCTP-protocols.patch b/SPECS/0002-libsemanage-Add-support-for-DCCP-and-SCTP-protocols.patch new file mode 100644 index 0000000..c94d9fc --- /dev/null +++ b/SPECS/0002-libsemanage-Add-support-for-DCCP-and-SCTP-protocols.patch @@ -0,0 +1,48 @@ +From d68976d353bf334c43fd084f9cc4535874860006 Mon Sep 17 00:00:00 2001 +From: Vit Mojzis +Date: Tue, 8 Oct 2019 14:22:12 +0200 +Subject: [PATCH] libsemanage: Add support for DCCP and SCTP protocols + +This is necessary for "semanage port" to be able to handle DCCP and SCTP +protocols. + +Fixes: + "port_parse" only handles TCP and UDP protocols + +Signed-off-by: Vit Mojzis +--- + libsemanage/include/semanage/port_record.h | 2 ++ + libsemanage/src/ports_file.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/libsemanage/include/semanage/port_record.h b/libsemanage/include/semanage/port_record.h +index 20ae4bd9..71074800 100644 +--- a/libsemanage/include/semanage/port_record.h ++++ b/libsemanage/include/semanage/port_record.h +@@ -16,6 +16,8 @@ typedef struct semanage_port_key semanage_port_key_t; + + #define SEMANAGE_PROTO_UDP 0 + #define SEMANAGE_PROTO_TCP 1 ++#define SEMANAGE_PROTO_DCCP 2 ++#define SEMANAGE_PROTO_SCTP 3 + + /* Key */ + extern int semanage_port_compare(const semanage_port_t * port, +diff --git a/libsemanage/src/ports_file.c b/libsemanage/src/ports_file.c +index 46ee2f00..4738d467 100644 +--- a/libsemanage/src/ports_file.c ++++ b/libsemanage/src/ports_file.c +@@ -84,6 +84,10 @@ static int port_parse(semanage_handle_t * handle, + semanage_port_set_proto(port, SEMANAGE_PROTO_TCP); + else if (!strcasecmp(str, "udp")) + semanage_port_set_proto(port, SEMANAGE_PROTO_UDP); ++ else if (!strcasecmp(str, "dccp")) ++ semanage_port_set_proto(port, SEMANAGE_PROTO_DCCP); ++ else if (!strcasecmp(str, "sctp")) ++ semanage_port_set_proto(port, SEMANAGE_PROTO_SCTP); + else { + ERR(handle, "invalid protocol \"%s\" (%s: %u):\n%s", str, + info->filename, info->lineno, info->orig_line); +-- +2.21.0 + diff --git a/SPECS/0003-libsemanage-fsync-final-files-before-rename.patch b/SPECS/0003-libsemanage-fsync-final-files-before-rename.patch new file mode 100644 index 0000000..b40686e --- /dev/null +++ b/SPECS/0003-libsemanage-fsync-final-files-before-rename.patch @@ -0,0 +1,156 @@ +From dc4f1d03d6e17d851283f9b10b2faeeca9b10e14 Mon Sep 17 00:00:00 2001 +From: Stephen Smalley +Date: Wed, 13 May 2020 15:34:19 -0400 +Subject: [PATCH] libsemanage: fsync final files before rename + +Prior to rename(2)'ing the final selinux policy files into place, +fsync(2) them to ensure the contents will be fully written prior to +rename. While we are here, also fix checking of write(2) to detect +short writes and treat them as an error. This code could be more +generally improved but keeping to the minimal changes required to fix +this bug. + +Fixes: https://github.com/SELinuxProject/selinux/issues/237 +Signed-off-by: Stephen Smalley +Acked-by: Nicolas Iooss + +Source: +https://github.com/SELinuxProject/selinux/commit/331a109f91ea46473fd858c2494f6eab1ef43f66 +--- + libsemanage/src/direct_api.c | 10 +++++----- + libsemanage/src/semanage_store.c | 20 +++++++++++++++----- + libsemanage/src/semanage_store.h | 4 +++- + 3 files changed, 23 insertions(+), 11 deletions(-) + +diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c +index 8e4d116d..abc3a4cb 100644 +--- a/libsemanage/src/direct_api.c ++++ b/libsemanage/src/direct_api.c +@@ -1188,7 +1188,7 @@ cleanup: + * overwrite it. If source doesn't exist then return success. + * Returns 0 on success, -1 on error. */ + static int copy_file_if_exists(const char *src, const char *dst, mode_t mode){ +- int rc = semanage_copy_file(src, dst, mode); ++ int rc = semanage_copy_file(src, dst, mode, false); + return (rc < 0 && errno != ENOENT) ? rc : 0; + } + +@@ -1481,7 +1481,7 @@ rebuild: + retval = semanage_copy_file(path, + semanage_path(SEMANAGE_TMP, + SEMANAGE_STORE_SEUSERS), +- 0); ++ 0, false); + if (retval < 0) + goto cleanup; + pseusers->dtable->drop_cache(pseusers->dbase); +@@ -1499,7 +1499,7 @@ rebuild: + retval = semanage_copy_file(path, + semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_EXTRA), +- 0); ++ 0, false); + if (retval < 0) + goto cleanup; + pusers_extra->dtable->drop_cache(pusers_extra->dbase); +@@ -1588,7 +1588,7 @@ rebuild: + + retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL), +- sh->conf->file_mode); ++ sh->conf->file_mode, false); + if (retval < 0) { + goto cleanup; + } +@@ -1627,7 +1627,7 @@ rebuild: + retval = semanage_copy_file( + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS), +- sh->conf->file_mode); ++ sh->conf->file_mode, false); + if (retval < 0) { + goto cleanup; + } +diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c +index 58dded6e..733df8da 100644 +--- a/libsemanage/src/semanage_store.c ++++ b/libsemanage/src/semanage_store.c +@@ -707,7 +707,8 @@ static int semanage_filename_select(const struct dirent *d) + + /* 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 semanage_copy_file(const char *src, const char *dst, mode_t mode, ++ bool syncrequired) + { + int in, out, retval = 0, amount_read, n, errsv = errno; + char tmp[PATH_MAX]; +@@ -735,8 +736,11 @@ int semanage_copy_file(const char *src, const char *dst, mode_t mode) + } + umask(mask); + while (retval == 0 && (amount_read = read(in, buf, sizeof(buf))) > 0) { +- if (write(out, buf, amount_read) < 0) { +- errsv = errno; ++ if (write(out, buf, amount_read) != amount_read) { ++ if (errno) ++ errsv = errno; ++ else ++ errsv = EIO; + retval = -1; + } + } +@@ -745,6 +749,10 @@ int semanage_copy_file(const char *src, const char *dst, mode_t mode) + retval = -1; + } + close(in); ++ if (syncrequired && fsync(out) < 0) { ++ errsv = errno; ++ retval = -1; ++ } + if (close(out) < 0) { + errsv = errno; + retval = -1; +@@ -811,7 +819,8 @@ static int semanage_copy_dir_flags(const char *src, const char *dst, int flag) + umask(mask); + } else if (S_ISREG(sb.st_mode) && flag == 1) { + mask = umask(0077); +- if (semanage_copy_file(path, path2, sb.st_mode) < 0) { ++ if (semanage_copy_file(path, path2, sb.st_mode, ++ false) < 0) { + umask(mask); + goto cleanup; + } +@@ -1640,7 +1649,8 @@ static int semanage_install_final_tmp(semanage_handle_t * sh) + goto cleanup; + } + +- ret = semanage_copy_file(src, dst, sh->conf->file_mode); ++ ret = semanage_copy_file(src, dst, sh->conf->file_mode, ++ true); + if (ret < 0) { + ERR(sh, "Could not copy %s to %s.", src, dst); + goto cleanup; +diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h +index 34bf8523..b9ec5664 100644 +--- a/libsemanage/src/semanage_store.h ++++ b/libsemanage/src/semanage_store.h +@@ -24,6 +24,7 @@ + #ifndef SEMANAGE_MODULE_STORE_H + #define SEMANAGE_MODULE_STORE_H + ++#include + #include + #include + #include +@@ -162,6 +163,7 @@ int semanage_nc_sort(semanage_handle_t * sh, + 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); ++int semanage_copy_file(const char *src, const char *dst, mode_t mode, ++ bool syncrequired); + + #endif +-- +2.25.4 + diff --git a/SPECS/libsemanage-2.9.tar.gz b/SPECS/libsemanage-2.9.tar.gz new file mode 100644 index 0000000..9f73aff Binary files /dev/null and b/SPECS/libsemanage-2.9.tar.gz differ diff --git a/SPECS/libsemanage.spec b/SPECS/libsemanage.spec new file mode 100644 index 0000000..d8b4c23 --- /dev/null +++ b/SPECS/libsemanage.spec @@ -0,0 +1,1483 @@ +%define libsepolver 2.9-1 +%define libselinuxver 2.9-1 + +Summary: SELinux binary policy manipulation library +Name: libsemanage +Version: 2.9 +Release: 3%{?dist} +License: LGPLv2+ +Source0: https://github.com/SELinuxProject/selinux/releases/download/20190315/libsemanage-2.9.tar.gz +# i=1; for j in 00*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done +Patch0001: 0001-libsemanage-Fix-RESOURCE_LEAK-and-USE_AFTER_FREE-cov.patch +Patch0002: 0002-libsemanage-Add-support-for-DCCP-and-SCTP-protocols.patch +Patch0003: 0003-libsemanage-fsync-final-files-before-rename.patch +URL: https://github.com/SELinuxProject/selinux/wiki +Source1: semanage.conf + +BuildRequires: gcc +BuildRequires: libselinux-devel >= %{libselinuxver} swig +BuildRequires: libsepol-devel >= %{libsepolver} +BuildRequires: audit-libs-devel +BuildRequires: bison flex bzip2-devel + +BuildRequires: python3 +BuildRequires: python3-devel + +Requires: bzip2-libs audit-libs +Requires: libselinux%{?_isa} >= %{libselinuxver} + +%description +Security-enhanced Linux is a feature of the Linux® kernel and a number +of utilities with enhanced security functionality designed to add +mandatory access controls to Linux. The Security-enhanced Linux +kernel contains new architectural components originally developed to +improve the security of the Flask operating system. These +architectural components provide 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. + +libsemanage provides an API for the manipulation of SELinux binary policies. +It is used by checkpolicy (the policy compiler) and similar tools, as well +as by programs like load_policy that need to perform specific transformations +on binary policies such as customizing policy boolean settings. + +%package static +Summary: Static library used to build policy manipulation tools +Requires: libsemanage-devel%{_isa} = %{version}-%{release} + +%description static +The semanage-static package contains the static libraries +needed for developing applications that manipulate binary policies. + +%package devel +Summary: Header files and libraries used to build policy manipulation tools +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The semanage-devel package contains the libraries and header files +needed for developing applications that manipulate binary policies. + +%package -n python3-libsemanage +Summary: semanage python 3 bindings for libsemanage +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: libselinux-python3 +%{?python_provide:%python_provide python3-libsemanage} +# Remove before F30 +Provides: %{name}-python3 = %{version}-%{release} +Provides: %{name}-python3%{?_isa} = %{version}-%{release} +Obsoletes: %{name}-python3 < %{version}-%{release} + +%description -n python3-libsemanage +The libsemanage-python3 package contains the python 3 bindings for developing +SELinux management applications. + +%prep +%autosetup -n libsemanage-%{version} -p 2 + + +%build +%set_build_flags + +# To support building the Python wrapper against multiple Python runtimes +# Define a function, for how to perform a "build" of the python wrapper against +# a specific runtime: +BuildPythonWrapper() { + BinaryName=$1 + + # Perform the build from the upstream Makefile: + make \ + PYTHON=$BinaryName \ + LIBDIR="%{_libdir}" SHLIBDIR="%{_lib}" \ + pywrap +} + +make clean +make swigify +make LIBDIR="%{_libdir}" SHLIBDIR="%{_lib}" all + +BuildPythonWrapper \ + %{__python3} + +%install +InstallPythonWrapper() { + BinaryName=$1 + + make \ + PYTHON=$BinaryName \ + DESTDIR="${RPM_BUILD_ROOT}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" \ + install-pywrap +} + +mkdir -p ${RPM_BUILD_ROOT}%{_libdir} +mkdir -p ${RPM_BUILD_ROOT}%{_includedir} +mkdir -p ${RPM_BUILD_ROOT}%{_sharedstatedir}/selinux +mkdir -p ${RPM_BUILD_ROOT}%{_sharedstatedir}/selinux/tmp +make DESTDIR="${RPM_BUILD_ROOT}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" install + +InstallPythonWrapper \ + %{__python3} \ + $(python3-config --extension-suffix) + +cp %{SOURCE1} ${RPM_BUILD_ROOT}/etc/selinux/semanage.conf +ln -sf %{_libdir}/libsemanage.so.1 ${RPM_BUILD_ROOT}/%{_libdir}/libsemanage.so + +pathfix.py -i "%{__python3} -E" -p %{buildroot}%{_libexecdir}/selinux/semanage_migrate_store +rm %{buildroot}%{_libexecdir}/selinux/semanage_migrate_store~ + +%files +%{!?_licensedir:%global license %%doc} +%license COPYING +%dir %{_sysconfdir}/selinux +%config(noreplace) %{_sysconfdir}/selinux/semanage.conf +%{_libdir}/libsemanage.so.1 +%{_mandir}/man5/* +%{_mandir}/ru/man5/* +%dir %{_libexecdir}/selinux +%dir %{_sharedstatedir}/selinux +%dir %{_sharedstatedir}/selinux/tmp + +%ldconfig_scriptlets + +%files static +%{_libdir}/libsemanage.a + +%files devel +%{_libdir}/libsemanage.so +%{_libdir}/pkgconfig/libsemanage.pc +%dir %{_includedir}/semanage +%{_includedir}/semanage/*.h +%{_mandir}/man3/* + +%files -n python3-libsemanage +%{python3_sitearch}/*.so +%{python3_sitearch}/semanage.py* +%{python3_sitearch}/__pycache__/semanage* +%{_libexecdir}/selinux/semanage_migrate_store + +%changelog +* Mon Jun 29 2020 Vit Mojzis - 2.9-3 +- Fsync final files before rename (#1838762) + +* Wed Nov 06 2019 Vit Mojzis - 2.9-2 +- Add support for DCCP and SCTP protocols (#1563742) + +* Mon Mar 18 2019 Petr Lautrbach - 2.9-1 +- SELinux userspace 2.9 release + +* Thu Dec 6 2018 Petr Lautrbach - 2.8-5 +- genhomedircon - improve handling large groups + +* Thu Nov 8 2018 Petr Lautrbach - 2.8-4 +- Fix RESOURCE_LEAK and USE_AFTER_FREE coverity scan defects + +* Mon Sep 17 2018 Petr Lautrbach - 2.8-3.1 +- reset umask before creating directories +- Include user name in ROLE_REMOVE audit events + +* Wed Jun 6 2018 Petr Lautrbach - 2.8-2 +- Don't build the Python 2 subpackage (#1567359) + +* Fri May 25 2018 Petr Lautrbach - 2.8-1 +- SELinux userspace 2.8 release + +* Mon May 14 2018 Petr Lautrbach - 2.8-0.rc3.1 +- SELinux userspace 2.8-rc3 release candidate + +* Fri May 4 2018 Petr Lautrbach - 2.8-0.rc2.1 +- SELinux userspace 2.8-rc2 release candidate + +* Mon Apr 23 2018 Petr Lautrbach - 2.8-0.rc1.1 +- SELinux userspace 2.8-rc1 release candidate + +* Wed Mar 21 2018 Petr Lautrbach - 2.7-12 +- build: Replace PYSITEDIR with PYTHONLIBDIR +- direct_api.c: Fix iterating over array (#1557468) + +* Fri Mar 16 2018 Petr Lautrbach - 2.7-11 +- Revert "remove access() check to make setuid programs work" (#1557468) + +* Tue Mar 13 2018 Petr Lautrbach - 2.7-10 +- properly check return value of iterate function +- Use umask(0077) for fopen() write operations +- Return commit number if save-previous false +- Allow tmp files to be kept if a compile fails +- build: follow standard semantics for DESTDIR and PREFIX +- Improve warning for installing disabled module +- silence clang static analyzer report +- remove access() check to make setuid programs work + +* Fri Feb 09 2018 Igor Gnatenko - 2.7-9 +- Escape macros in %%changelog + +* Wed Feb 07 2018 Fedora Release Engineering - 2.7-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Feb 03 2018 Igor Gnatenko - 2.7-7 +- Switch to %%ldconfig_scriptlets + +* Tue Jan 09 2018 Iryna Shcherbina - 2.7-6 +- Update Python 2 dependency declarations to new packaging standards + (See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3) + +* Wed Nov 22 2017 Petr Lautrbach - 2.7-5 +- free genhomedircon fallback user +- Rebuild with libsepol-2.7-3 and libselinux-2.7-6 + +* Fri Oct 20 2017 Petr Lautrbach - 2.7-4 +- Add support for listing fcontext.homedirs file (#1409813) + +* Sun Aug 20 2017 Zbigniew Jędrzejewski-Szmek - 2.7-3 +- Add Provides for the old names without %%_isa + +* Thu Aug 10 2017 Zbigniew Jędrzejewski-Szmek - 2.7-2 +- Python 2 binary package renamed to python2-libsemanage + See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3 +- Python 3 binary package renamed to python3-libsemanage + +* Mon Aug 07 2017 Petr Lautrbach - 2.7-1 +- Update to upstream release 2017-08-04 +- Use 'sefcontext_compile -r' when it's run during SELinux policy build + +* Thu Aug 03 2017 Fedora Release Engineering - 2.6-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 2.6-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Apr 28 2017 Petr Lautrbach - 2.6-4 +- Follow upstream and rename _semanage.so to _semanage.cpython-36m-x86_64-linux-gnu.so + +* Tue Apr 18 2017 Petr Lautrbach - 2.6-3 +- Do not list duplicate port entries after setting a boolean (#1439875) + +* Thu Mar 02 2017 Petr Lautrbach - 2.6-2 +- Fix FTBFS - fatal error (#1427903) + +* Mon Feb 20 2017 Petr Lautrbach - 2.6-1.1 +- Update to upstream release 2016-10-14 + +* Fri Feb 10 2017 Fedora Release Engineering - 2.5-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Dec 09 2016 Charalampos Stratakis - 2.5-9 +- Rebuild for Python 3.6 + +* Mon Oct 03 2016 Petr Lautrbach 2.5-8 +- Fixes bug preventing the installation of base modules +- make distclean target work +- Do not always print a module name warning +- Use pp module name instead of filename when installing module +- tests: Do not force using gcc +- genhomedircon: remove hardcoded refpolicy strings +- genhomedircon: add support for %%group syntax +- genhomedircon: generate contexts for logins mapped to the default user +- Validate and compile file contexts before installing +- Swap tcp and udp protocol numbers + +* Mon Aug 01 2016 Petr Lautrbach 2.5-7 +- Rebuilt with libsepol-2.5-9 and libselinux-2.5-11 + +* Tue Jul 19 2016 Fedora Release Engineering - 2.5-6 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Thu Jun 23 2016 Petr Lautrbach - 2.5-5 +- Sort object files for deterministic linking order +- Support overriding Makefile RANLIB +- Respect CC and PKG_CONFIG environment variable + +* Fri May 06 2016 Petr Lautrbach - 2.5-4 +- Fix multiple spelling errors +- genhomedircon: %%{USERID} and %%{USERNAME} support and code cleanup + +* Mon Mar 21 2016 Petr Lautrbach - 2.5-3 +- Enable expand-check by default (#1319652) + +* Sun Feb 28 2016 Petr Lautrbach 2.5-2 +- Use fully versioned arch-specific requires + +* Tue Feb 23 2016 Petr Lautrbach 2.5-1 +- Update to upstream release 2016-02-23 + +* Sun Feb 21 2016 Petr Lautrbach 2.5-0.1.rc1 +- Update to upstream rc1 release 2016-01-07 + +* Thu Feb 04 2016 Fedora Release Engineering - 2.4-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Nov 04 2015 Robert Kuska - 2.4-5 +- Rebuilt for Python3.5 rebuild + +* Fri Sep 04 2015 Petr Lautrbach 2.4-4 +- Save homedir_template in the policy store for genhomedircon + https://bugs.gentoo.org/558686 + +* Fri Aug 14 2015 Adam Jackson 2.4-3 +- Pass ldflags into the build so hardening works + +* Thu Jul 30 2015 Petr Lautrbach 2.4-2 +- semanage_migrate_store: use /usr/bin/python3 +- move semanage_migrate_store script to libsemanage-python3 + +* Wed Jun 24 2015 Petr Lautrbach 2.4-0.6 +- Allow to use compressed modules without a compression extension + +* Wed Jun 17 2015 Fedora Release Engineering - 2.3-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue Jun 16 2015 Petr Lautrbach 2.4-0.5 +- add /var/lib/selinux/tmp directory + +* Tue May 12 2015 Petr Lautrbach 2.4-0.4 +- semanage_migrate_store: add -r option for migrating inside chroots + +* Mon Apr 13 2015 Petr Lautrbach 2.4-0.3 +- Update to upstream release 2.4 + +* Sun Aug 17 2014 Fedora Release Engineering - 2.3-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Wed Jul 30 2014 Miroslav Grepl - 2.3-5 +- Skip policy module re-link when only setting booleans. + * patch from Stephen Smalley + +* Fri Jul 18 2014 Tom Callaway - 2.3-4 +- fix license handling + +* Sat Jun 07 2014 Fedora Release Engineering - 2.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Kalev Lember - 2.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* Tue May 6 2014 Dan Walsh - 2.3-1 +- Update to upstream + * Fix memory leak in semanage_genhomedircon from Thomas Hurd. + +* Sun Mar 30 2014 Dan Walsh - 2.2-3 +- libsemanage: fix memory leak in semanage_genhomedircon +- Patch from THomas Hurd + +* Tue Feb 11 2014 Dan Walsh - 2.2-2 +- Move semanage.conf man page from devel package to main package + +* Thu Oct 31 2013 Dan Walsh - 2.2-1 +- Update to upstream + * 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. + +* Wed Oct 16 2013 Dan Walsh - 2.1.10-14 +- Cleanup handling of missing mls_range to fix problems with useradd -Z +- Fix auditing of login record changes, roles were not working correctly. +Resolves: #952237 + +* Fri Oct 4 2013 Dan Walsh - 2.1.10-13 +- Fix errors found by coverity +Resolves: #952237 + +* Wed Sep 25 2013 Dan Walsh - 2.1.10-12 +- Do not fail on missing SELinux User Record when adding login record + +* Mon Sep 23 2013 Dan Walsh - 2.1.10-11 +- Add msg to audit records + +* Thu Sep 19 2013 Dan Walsh - 2.1.10-10 +- Do not write error message to screen when looking for previous record for auditing. +- Add mls_range from user record if the MLS range is not specified by the seuser add record. +- Error out if seuser or mls range is not specified when adding user records + +* Mon Sep 9 2013 Dan Walsh - 2.1.10-9 +- Create symlink from policy.kern to active kernel. + +* Fri Sep 6 2013 Dan Walsh - 2.1.10-8 +- Unlink policy.kern when done to save space. + +* Fri Jul 26 2013 Dan Walsh - 2.1.10-7 +- Move handling of role audit records into the library +- Patch stops semanage from removing user record while in use + +* Tue Jul 9 2013 Dan Walsh - 2.1.10-6 +- Remove dependance on selinux-policy, /etc/selinux should be owned by libsemanage, and selinux-policy can require it. + +* Fri Jun 28 2013 Dan Walsh - 2.1.10-5 +- Allways build python3 version + +* Mon Apr 22 2013 Dan Walsh - 2.1.10-4 +- + +* Thu Apr 11 2013 Dan Walsh - 2.1.10-3 +- Fix test suite to build + +* Thu Feb 14 2013 Dan Walsh - 2.1.10-2 +- Revert some changes which are causing the wrong policy version file to be created + +* Thu Feb 7 2013 Dan Walsh - 2.1.10-1 +- Update to upstream + * 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 + +* Wed Jan 16 2013 Dan Walsh 2.1.9-4 +- Add selinux-policy as a requires to get /etc/selinux owned + +* Sat Jan 5 2013 Dan Walsh 2.1.9-3 +- Update to latest patches from eparis/Upstream +- libsemanage: fixes from coverity +- libsemange: redo genhomedircon minuid + +* Wed Nov 21 2012 Dan Walsh - 2.1.9-2 +- Fix handling of missing semanage permissive -d foo, not failing correctly +- Previous to this fix the first module beginning with foo would get deleted. + +* Thu Sep 13 2012 Dan Walsh - 2.1.9-1 +- Update to upstream + * libsemanage: do not set soname needlessly + * libsemanage: remove PYTHONLIBDIR and ruby equivalent + * do boolean name substitution + * Fix segfault for building standard policies. + +* Fri Aug 03 2012 David Malcolm - 2.1.8-6 +- rebuild for https://fedoraproject.org/wiki/Features/Python_3.3 + +* Wed Aug 1 2012 David Malcolm - 2.1.8-5 +- remove rhel logic from with_python3 conditional + +* Thu Jul 19 2012 Fedora Release Engineering - 2.1.8-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Jul 13 2012 Dan Walsh - 2.1.8-3 +- Attempt to allocate memory for selinux_binary_policy_path and free memory +- allocated by asprintf. + +* Thu Jul 12 2012 Dan Walsh - 2.1.8-2 +- Fix asprintf within an asprintf call + +* Wed Jul 4 2012 Dan Walsh - 2.1.8-1 +- Update to upstream + * 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 + +* Tue May 29 2012 Dan Walsh - 2.1.7-2 +- Apply patch from Sven Vermeulen to fix problem with python3 bindings. + +* Thu Mar 29 2012 Dan Walsh - 2.1.7-1 +- Update to upstream + * 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 + +* Wed Feb 15 2012 Dan Walsh - 2.1.6-3 +- Check in correct patch. + +* Fri Jan 13 2012 Fedora Release Engineering - 2.1.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Fri Jan 6 2012 Dan Walsh - 2.1.6-2 +- Add patch form Xin Ouyang to make library use private semanage.conf + +* Wed Dec 21 2011 Dan Walsh - 2.1.6-1 +-Update to upstream + * add ignoredirs config for genhomedircon + * Fallback_user_level can be NULL if you are not using MLS + +* Thu Dec 15 2011 Dan Walsh - 2.1.5-4 +- Rebuild with latest libsepol + +* Thu Dec 15 2011 Dan Walsh - 2.1.5-3 +- Rebuild with latest libsepol + +* Thu Dec 15 2011 Dan Walsh - 2.1.5-2 +- Add support for ignoredirs param in /etc/selinux/semanage.conf + +* Fri Nov 4 2011 Dan Walsh - 2.1.5-1 +- Upgrade to upstream + * regenerate .pc on VERSION change + * maintain mode even if umask is tighter + * semanage.conf man page + * create man5dir if not exist + +* Wed Oct 19 2011 Dan Walsh - 2.1.4-2 +- Fix handling of umask, so files get created with the correct label. + +* Mon Sep 19 2011 Dan Walsh - 2.1.4-2 +- Add Guido Trentalancia semanage.conf man page + +* Mon Sep 19 2011 Dan Walsh - 2.1.4-1 +-Update to upstream + * Create a new preserve_tunables flag + * tree: default make target to all not + * fix semanage_store_access_check calling arguments + +* Wed Sep 14 2011 Dan Walsh - 2.1.3-2 +- Add support for preserving tunables + +* Tue Aug 30 2011 Dan Walsh - 2.1.3-1 +-Update to upstream + * python wrapper makefile changes + +* Thu Aug 18 2011 Dan Walsh - 2.1.2-1 +-Update to upstream +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 + +* Thu Jul 28 2011 Dan Walsh - 2.1.0-1 +- Update to upstream + * Release, minor version bump + +* Wed Jun 8 2011 Dan Walsh - 2.0.46-6 +- More fixes for disabled modules + +* Tue Jun 7 2011 Dan Walsh - 2.0.46-5 +- Change libsemanage mechanism for handling disabled modules. Now it will only create a flag for a module +indicating the module is disabled. MODULE.pp.disabled, it will no longer rename the module. This way we can +ship active modules in rpm. + +* Wed Jun 1 2011 Dan Walsh - 2.0.46-4 +- Add semanage_set_selinux_path, to allow semodule to work on alternate selinux pools + +* Tue Feb 08 2011 Fedora Release Engineering - 2.0.46-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Dec 30 2010 David Malcolm - 2.0.46-2 +- big reworking of the support-multiple-python-builds patch to deal with +PEP 3149: the latest Python 3.2 onwards uses include paths and library names +that don't fit prior naming patterns, and so we must query python3-config for +this information. To complicate things further, python 2's python-config +doesn't understand all of the options needed ("--extension-suffix"). I've +thus added new Makefile variables as needed, to be supplied by the specfile by +invoking the appropriate config tool (or by hardcoding the old value for +"--extension-suffix" i.e. ".so") +- rework python3 manifest for PEP 3149, and rebuild for newer python3 + +* Tue Dec 21 2010 Dan Walsh - 2.0.46-1 +- Update to upstream + * Fix compliation under GCC 4.6 by Justin Mattock + +* Wed Aug 25 2010 Thomas Spura - 2.0.45-6 +- rebuild with python3.2 + http://lists.fedoraproject.org/pipermail/devel/2010-August/141368.html + +* Wed Jul 21 2010 David Malcolm - 2.0.45-5 +- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild + +* Tue Apr 27 2010 David Malcolm - 2.0.45-4 +- add python3 subpackage + +* Wed Apr 7 2010 Dan Walsh - 2.0.45-3 +- Fix -devel package to point at the correct shared library + +* Fri Mar 26 2010 Dan Walsh - 2.0.45-2 +- Move shared library to /usr/lib + +* Mon Mar 8 2010 Dan Walsh - 2.0.45-1 +- Update to upstream + * 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 + +* Thu Feb 25 2010 Dan Walsh - 2.0.44-2 +- Allow disable of usepasswd + +* Wed Feb 17 2010 Dan Walsh - 2.0.44-1 +- Update to upstream + * Replace usage of fmemopen() with sepol_policy_file_set_mem() since + glibc < 2.9 does not support binary mode ('b') for fmemopen'd + streams. + +* Thu Jan 28 2010 Dan Walsh - 2.0.43-4 +- Cleanup spec file + +* Mon Jan 18 2010 Dan Walsh - 2.0.43-3 +- Splect libsemanage.a into a static subpackage to keep fedora packaging guidelines happy + +* Wed Dec 16 2009 Dan Walsh - 2.0.43-2 +- Rebuild all c programs with -fPIC + +* Tue Dec 1 2009 Dan Walsh - 2.0.43-1 +- Update to upstream + * Move libsemanage.so to /usr/lib + * Add NAME lines to man pages from Manoj Srivastava + +* Wed Nov 18 2009 Dan Walsh - 2.0.42-1 +- Update to upstream + * Move load_policy from /usr/sbin to /sbin from Dan Walsh. + +* Mon Nov 2 2009 Dan Walsh - 2.0.41-1 +- Update to upstream + * Add pkgconfig file from Eamon Walsh. + * Add semanage_set_check_contexts() function to disable calling + setfiles + +* Mon Sep 28 2009 Dan Walsh - 2.0.39-1 +- Update to upstream + * make swigify + +* Sun Sep 20 2009 Dan Walsh - 2.0.38-2 +- Dont relabel /root with genhomedircon + +* Thu Sep 17 2009 Dan Walsh - 2.0.38-1 +- Update to upstream + * 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. + +* Wed Sep 9 2009 Dan Walsh - 2.0.37-1 +- Update to upstream + * Fix persistent dontaudit support to rebuild policy if the + dontaudit state is changed from Chad Sellers. +- Move load_policy to /sbin + +* Fri Aug 28 2009 Dan Walsh - 2.0.36-2 +- Add enable/disable modules + +* Wed Aug 26 2009 Dan Walsh - 2.0.36-1 +- Update to upstream + * Changed bzip-blocksize=0 handling to support existing compressed + modules in the store. + +* Wed Aug 26 2009 Dan Walsh - 2.0.35-2 +- Make sure /root is not used in genhomedircon + +* Wed Aug 5 2009 Dan Walsh - 2.0.35-1 +- Revert hard linking of files between tmp/active/previous. +- 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. + +* Sat Jul 25 2009 Fedora Release Engineering - 2.0.33-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Fri Jul 10 2009 Dan Walsh - 2.0.33-2 +- Put check for /root back into genhomedircon + +* Tue Jul 7 2009 Dan Walsh - 2.0.33-1 +- Update to upstream + +* Mon Jun 8 2009 Dan Walsh - 2.0.32-1 +- Update to upstream + * Ruby bindings from David Quigley. + +* Thu Apr 9 2009 Dan Walsh - 2.0.31-5 +- Return error on invalid file + +* Wed Mar 11 2009 Dan Walsh - 2.0.31-4 +- Fix typo + +* Wed Feb 25 2009 Fedora Release Engineering - 2.0.31-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Jan 15 2009 Dan Walsh - 2.0.31-2 +- Fix link to only link on sandbox + +* Mon Jan 12 2009 Dan Walsh - 2.0.31-1 +- Update to upstream + * Policy module compression (bzip) support from Dan Walsh. + * Hard link files between tmp/active/previous from Dan Walsh. + +* Mon Jan 12 2009 Dan Walsh - 2.0.30-3 +- Fix up patch to get it upstreamed + +* Thu Dec 04 2008 Ignacio Vazquez-Abrams - 2.0.30-2 +- Rebuild for Python 2.6 + +* Thu Dec 4 2008 Dan Walsh - 2.0.30-1 +- Add semanage_mls_enabled() interface from Stephen Smalley. + +* Sat Nov 29 2008 Ignacio Vazquez-Abrams - 2.0.29-2 +- Rebuild for Python 2.6 + +* Mon Sep 15 2008 Dan Walsh - 2.0.28-1 +- Update to upstream + * Add USER to lines to homedir_template context file from Chris PeBenito. + +* Mon Sep 15 2008 Dan Walsh - 2.0.28-2 +- Add compression support + +* Mon Sep 15 2008 Dan Walsh - 2.0.28-1 +- Update to upstream + * allow fcontext and seuser changes without rebuilding the policy from Dan Walsh + +* Wed Sep 10 2008 Dan Walsh - 2.0.27-3 +- Additional fixes for Don't rebuild on fcontext or seuser modifications + +* Tue Sep 2 2008 Dan Walsh - 2.0.27-2 +- Don't rebuild on fcontext or seuser modifications + +* Tue Aug 5 2008 Dan Walsh - 2.0.27-1 +- Update to upstream + * 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. + +* Tue Jul 29 2008 Dan Walsh - 2.0.26-1 +- Update to upstream + * Fix bug in genhomedircon fcontext matches logic from Dan Walsh. + Strip any trailing slash before appending /*$. + +* Tue Jun 17 2008 Dan Walsh - 2.0.25-3 +- Another fix for genhomedircon + +* Wed May 28 2008 Tom "spot" Callaway - 2.0.25-2 +- fix license tag + +* Tue Feb 5 2008 Dan Walsh - 2.0.25-1 +- Update to upstream + * Do not call genhomedircon if the policy was not rebuilt from Stephen Smalley. + Fixes semanage boolean -D seg fault (bug 441379). + +* Tue Feb 5 2008 Dan Walsh - 2.0.24-1 +- Update to upstream + * make swigify + +* Tue Feb 5 2008 Dan Walsh - 2.0.23-1 +- Update to upstream + * Use vfork rather than fork for libsemanage helpers to reduce memory overhead as suggested by Todd Miller. + +* Mon Feb 4 2008 Dan Walsh - 2.0.22-1 +- Update to upstream + * Free policydb before fork from Joshua Brindle. + * Drop the base module immediately after expanding to permit memory re-use from Stephen Smalley. + +* Sat Feb 2 2008 Dan Walsh - 2.0.20-1 +- Update to upstream + * Use sepol_set_expand_consume_base to reduce peak memory usage when + using semodule + +* Fri Feb 1 2008 Dan Walsh - 2.0.19-1 +- Update to upstream + * Fix genhomedircon to not override a file context with a homedir context from Todd Miller. + +* Tue Jan 29 2008 Dan Walsh - 2.0.18-1 +- Update to upstream + * Fix spurious out of memory error reports. + * Merged second version of fix for genhomedircon handling from Caleb Case. + +* Tue Jan 22 2008 Dan Walsh - 2.0.16-1 +- Update to upstream + * Merged fix for genhomedircon handling of missing HOME_DIR or HOME_ROOT templates from Caleb Case. + +* Tue Jan 22 2008 Dan Walsh - 2.0.15-2 +- Stop differentiating on user for homedir labeling + +* Thu Dec 6 2007 Dan Walsh - 2.0.15-1 +- Update to upstream + * Fix genhomedircon handling of shells and missing user context template from Dan Walsh. + * Copy the store path in semanage_select_store from Dan Walsh. +- Add expand-check=0 to semanage.conf + +* Mon Dec 3 2007 Dan Walsh - 2.0.14-5 +- Fix handling of /etc/shells so genhomedircon will work + +* Thu Nov 29 2007 Dan Walsh - 2.0.14-3 +- Allow semanage_genhomedircon to work with out a USER int homedir.template + +* Sat Nov 10 2007 Dan Walsh - 2.0.14-2 +- Fix semanage_select_store to allocate memory, fixes crash on invalid store + +* Tue Nov 6 2007 Dan Walsh - 2.0.14-1 +- Upgrade to latest from NSA + * Call rmdir() rather than remove() on directory removal so that errno isn't polluted from Stephen Smalley. + * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley. + +* Fri Oct 5 2007 Dan Walsh - 2.0.12-1 +- Upgrade to latest from NSA + * ustr cleanups from James Antill. + * Ensure that /root gets labeled even if using the default context from Dan Walsh. + +* Fri Sep 28 2007 Dan Walsh - 2.0.11-1 +- Upgrade to latest from NSA + * Fix ordering of file_contexts.homedirs from Todd Miller and Dan Walsh. + +* Fri Sep 28 2007 Dan Walsh - 2.0.10-2 +- Fix sort order on generated homedir context + +* Fri Sep 28 2007 Dan Walsh - 2.0.10-1 +- Upgrade to latest from NSA + * 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. + +* Wed Sep 26 2007 Dan Walsh - 2.0.9-1 +- Upgrade to latest from NSA + * Pass CFLAGS to CC even on link command, per Dennis Gilmore. + * Clear errno on non-fatal errors to avoid reporting them upon a + later error that does not set errno. + * Improve reporting of system errors, e.g. full filesystem or read-only filesystem from Stephen Smalley. + +- Fix segfault in genhomedircon when using bad user names + +* Wed Sep 26 2007 Dan Walsh - 2.0.6-2 +- Fix genhomedircon code to only generate valid context +- Fixes autorelabel problem + +* Thu Sep 13 2007 Dan Walsh - 2.0.6-1 +- Upgrade to latest from NSA + * Change to use getpw* function calls to the _r versions from Todd Miller. + +* Thu Aug 23 2007 Dan Walsh - 2.0.5-1 +- Upgrade to latest from NSA + +* Mon Aug 20 2007 Dan Walsh - 2.0.4-1 +- Upgrade to latest from NSA + * Allow dontaudits to be turned off via semanage interface when + updating policy + +* Sat Aug 11 2007 Dan Walsh - 2.0.3-5 +- Add ability to load a policy without dontaudit rules +- + +* Tue Jun 26 2007 Dan Walsh - 2.0.3-4 +- Rebuild to fix segfault on x86 platforms, swigify on each build + +* Fri Jun 1 2007 Dan Walsh - 2.0.3-3 +- Rebuild for rawhide + +* Thu May 3 2007 Dan Walsh - 2.0.3-2 +- Apply patch to fix dependencies in spec file from Robert Scheck + +* Wed Apr 25 2007 Dan Walsh - 2.0.3-1 +- Upgrade to latest from NSA + * Fix to libsemanage man patches so whatis will work better from Dan Walsh + +* Wed Apr 25 2007 Dan Walsh - 2.0.2-1 +- Upgrade to latest from NSA +- 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 + +* Sat Mar 17 2007 Dan Walsh - 2.0.1-2 +- Add SELinux to Man page Names so man -k will work + +* Mon Mar 12 2007 Dan Walsh - 2.0.1-1 +- 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. + +* Tue Feb 20 2007 Dan Walsh - 2.0.0-1 +- Upgrade to latest from NSA + * 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. + +* Wed Feb 7 2007 Dan Walsh - 1.10.1-1 +- Upgrade to latest from NSA + * Merged python binding fix from Dan Walsh. + * Updated version for stable branch. + +* Fri Dec 22 2006 Dan Walsh - 1.9.2-1 +- Upgrade to latest from NSA + * 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 + +* Fri Dec 22 2006 Dan Walsh - 1.9.1-3 +- Apply Karl MacMillan patch to get proper error codes. + +* Thu Dec 7 2006 Jeremy Katz - 1.9.1-2 +- rebuild against python 2.5 + +* Tue Nov 28 2006 Dan Walsh - 1.9.1-1 +- Upgrade to latest from NSA + * 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. + +* Tue Oct 17 2006 Dan Walsh - 1.8-1 +- Upgrade to latest from NSA + * Updated version for release. + +* Thu Aug 31 2006 Dan Walsh - 1.6.17-1 +- Upgrade to latest from NSA + * 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. + +* Thu Aug 31 2006 Dan Walsh - 1.6.16-3 +- Fix semanage to not load if is not the correct policy type and it is installing + +* Thu Aug 31 2006 Dan Walsh - 1.6.16-2 +- Fix requires lines + +* Wed Aug 23 2006 Dan Walsh - 1.6.16-1 +- Upgrade to latest from NSA + * 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. + +* Sat Aug 12 2006 Dan Walsh - 1.6.15-1 +- Upgrade to latest from NSA + * Merged separate local file contexts patch from Chris PeBenito. + * Merged patch to make most copy errors non-fatal from Dan Walsh. + +* Thu Aug 10 2006 Dan Walsh - 1.6.13-3 +- Change other updates to be non-fatal + +* Wed Aug 9 2006 Dan Walsh - 1.6.13-2 +- Change netfilter stuff to be non-fatal so update can proceed. + +* Thu Aug 3 2006 Dan Walsh - 1.6.13-1 +- Upgrade to latest from NSA + * Merged netfilter contexts support from Chris PeBenito. + +* Mon Jul 17 2006 Dan Walsh - 1.6.12-2 +- Rebuild for new gcc + +* Tue Jul 11 2006 Dan Walsh - 1.6.12-1 +- Upgrade to latest from NSA + * Merged support for read operations on read-only fs from + Caleb Case (Tresys Technology). + +* Tue Jul 4 2006 Dan Walsh - 1.6.11-1 +- Upgrade to latest from NSA + * Lindent. + * Merged setfiles location check patch from Dan Walsh. + +* Fri Jun 16 2006 Dan Walsh - 1.6.9-1 +- Upgrade to latest from NSA + * 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 + +* Fri Jun 16 2006 Dan Walsh - 1.6.8-2 +- Handle setfiles being in /sbin or /usr/sbin + +* Mon May 15 2006 Dan Walsh - 1.6.8-1 +- Upgrade to latest from NSA + * 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] + +* Mon May 15 2006 Dan Walsh - 1.6.7-3 +- Spec file cleanup from n0dalus+redhat@gmail.com + +* Mon May 15 2006 Dan Walsh - 1.6.7-2 +- Add /usr/include/semanage to spec file + +* Mon May 8 2006 Dan Walsh - 1.6.7-1 +- Upgrade to latest from NSA + * Merged fix warnings patch from Karl MacMillan. + +* Fri Apr 14 2006 Dan Walsh - 1.6.6-1 +- Upgrade to latest from NSA + * Merged updated file context sorting patch from Christopher + Ashworth, with bug fix for escaped character flag. + * Merged file context sorting code from Christopher Ashworth + (Tresys Technology), based on fc_sort.c code in refpolicy. + * Merged python binding t_output_helper removal patch from Dan Walsh. + * Regenerated swig files. + +* Wed Mar 29 2006 Dan Walsh - 1.6.3-1 +- Fix to work with new version of swig +- Upgrade to latest from NSA + * Merged corrected fix for descriptor leak from Dan Walsh. + +* Wed Mar 29 2006 Dan Walsh - 1.6.2-2 +- Fix leaky descriptor + +* Tue Mar 21 2006 Dan Walsh - 1.6.2-1 +- Upgrade to latest from NSA + * Merged Makefile PYLIBVER definition patch from Dan Walsh. + * Merged man page reorganization from Ivan Gyurdiev. + +* Fri Mar 17 2006 Dan Walsh - 1.6-1 +- Make work on RHEL4 +- Upgrade to latest from NSA + * Merged abort early on merge errors patch from Ivan Gyurdiev. + * Cleaned up error handling in semanage_split_fc based on a patch + by Serge Hallyn (IBM) and suggestions by Ivan Gyurdiev. + * Merged MLS handling fixes from Ivan Gyurdiev. + +* Fri Feb 17 2006 Dan Walsh - 1.5.28-1 +- Upgrade to latest from NSA + * Merged bug fix for fcontext validate handler from Ivan Gyurdiev. + * Merged base_merge_components changes from Ivan Gyurdiev. + +* Thu Feb 16 2006 Dan Walsh - 1.5.26-1 +- Upgrade to latest from NSA + * Merged paths array patch from Ivan Gyurdiev. + * Merged bug fix patch from Ivan Gyurdiev. + * Merged improve bindings patch from Ivan Gyurdiev. + * 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. + +* Mon Feb 13 2006 Dan Walsh - 1.5.23-1 +- Upgrade to latest from NSA + * Merged optionals in base patch from Joshua Brindle. + * Merged treat seusers/users_extra as optional sections patch from + Ivan Gyurdiev. + * Merged parse_optional fixes from Ivan Gyurdiev. + +* Fri Feb 10 2006 Jesse Keating - 1.5.21-2.1 +- bump again for double-long bug on ppc(64) + +* Fri Feb 10 2006 Dan Walsh - 1.5.21-2 +- Fix handling of seusers and users_map file + +* Tue Feb 07 2006 Dan Walsh - 1.5.21-1 +- Upgrade to latest from NSA + * Merged seuser/user_extra support patch from Joshua Brindle. + * Merged remote system dbase patch from Ivan Gyurdiev. + +* Tue Feb 07 2006 Jesse Keating - 1.5.20-1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Thu Feb 2 2006 Dan Walsh 1.5.20-1 +- Upgrade to latest from NSA + * Merged clone record on set_con patch from Ivan Gyurdiev. + +* Mon Jan 30 2006 Dan Walsh 1.5.19-1 +- Upgrade to latest from NSA + * 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. + +* Fri Jan 27 2006 Dan Walsh 1.5.18-1 +- Upgrade to latest from NSA + * Merged seuser -> seuser_local rename patch from Ivan Gyurdiev. + * Merged set_create_store, access_check, and is_connected interfaces + from Joshua Brindle. + +* Fri Jan 13 2006 Dan Walsh 1.5.16-1 +- Upgrade to latest from NSA + * Regenerate python wrappers. + +* Fri Jan 13 2006 Dan Walsh 1.5.15-1 +- Upgrade to latest from NSA + * 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. + +* Fri Jan 13 2006 Dan Walsh 1.5.14-2 +- Break out python out of regular Makefile + +* Fri Jan 13 2006 Dan Walsh 1.5.14-1 +- Upgrade to latest from NSA + * Merged disallow port overlap patch from Ivan Gyurdiev. + * 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. + * 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. + +* Sat Jan 7 2006 Dan Walsh 1.5.9-1 +- Upgrade to latest from NSA + * 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. + +* Fri Jan 6 2006 Dan Walsh 1.5.8-1 +- Upgrade to latest from NSA + * Re-applied string and file optimization patch from Russell Coker, + with bug fix. + * Reverted string and file optimization patch from Russell Coker. + * Clarified error messages from parse_module_headers and + parse_base_headers for base/module mismatches. + +* Fri Jan 6 2006 Dan Walsh 1.5.6-1 +- Upgrade to latest from NSA + * Clarified error messages from parse_module_headers and + parse_base_headers for base/module mismatches. + * 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. + +* Thu Jan 5 2006 Dan Walsh 1.5.4-2 +- Patch to fix add + +* Thu Jan 5 2006 Dan Walsh 1.5.4-1 +- Upgrade to latest from NSA + * 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 + +* Tue Dec 27 2005 Dan Walsh 1.5.3-3 +- Add Ivans patch to turn on ports + +* Wed Dec 14 2005 Dan Walsh 1.5.3-2 +- Remove patch since upstream does the right thing + +* Wed Dec 14 2005 Dan Walsh 1.5.3-1 +- Upgrade to latest from NSA + * Merged further header cleanups from Ivan Gyurdiev. + * 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. + +* Tue Dec 13 2005 Dan Walsh 1.5.1-2 +- Upgrade to latest from NSA + * 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. + +* Mon Dec 12 2005 Dan Walsh 1.5.1-1 +- Upgrade to latest from NSA + * 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. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Wed Dec 7 2005 Dan Walsh 1.4-1 +- Fix mode of output seusers file + +* Tue Dec 6 2005 Dan Walsh 1.3.64-1 +- Upgrade to latest from NSA + * 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. + +* Mon Dec 5 2005 Dan Walsh 1.3.63-1 +- Upgrade to latest from NSA + * Dropped handle from user_del_role interface. + * Removed defrole interfaces. + +* Tue Nov 29 2005 Dan Walsh 1.3.61-1 +- Upgrade to latest from NSA + * Merged Makefile python definitions patch from Dan Walsh. + * Removed is_selinux_mls_enabled() conditionals in seusers and users + file parsers. + +* Wed Nov 23 2005 Dan Walsh 1.3.59-1 +- Add additional swig objects + * Merged wrap char*** for user_get_roles patch from Joshua Brindle. + * Merged remove defrole from sepol patch from Ivan Gyurdiev. + * Merged swig wrappers for modifying users and seusers from Joshua Brindle. + +* Wed Nov 23 2005 Dan Walsh 1.3.56-2 +- Add additional swig objects + +* Wed Nov 16 2005 Dan Walsh 1.3.56-1 +- Upgrade to latest from NSA + * Fixed free->key_free bug. + * Merged clear obsolete patch from Ivan Gyurdiev. + * Merged modified swigify patch from Dan Walsh + (original patch from Joshua Brindle). + * Merged move genhomedircon call patch from Chad Sellers. + +* Mon Nov 14 2005 Dan Walsh 1.3.53-3 +- Add genhomedircon patch from Joshua Brindle + +* Fri Nov 11 2005 Dan Walsh 1.3.53-2 +- Add swigify patch from Joshua Brindle + +* Fri Nov 11 2005 Dan Walsh 1.3.53-1 +- Upgrade to latest from NSA + * Merged move seuser validation patch from Ivan Gyurdiev. + * Merged hidden declaration fixes from Ivan Gyurdiev, + with minor corrections. + +* Wed Nov 9 2005 Dan Walsh 1.3.52-1 +- Upgrade to latest from NSA + * 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). + +* Tue Nov 8 2005 Dan Walsh 1.3.51-1 +- Upgrade to latest from NSA + * Clear modules modified flag upon disconnect and commit. + * Added tracking of module modifications and use it to + determine whether expand-time checks should be applied + on commit. + * Reverted semanage_set_reload_bools() interface. + +* Tue Nov 8 2005 Dan Walsh 1.3.48-1 +- Upgrade to latest from NSA + * Disabled calls to port dbase for merge and commit and stubbed + out calls to sepol_port interfaces since they are not exported. + * Merged rename instead of copy patch from Joshua Brindle (Tresys). + * 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. + * 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. + * 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. + +* Mon Nov 7 2005 Dan Walsh 1.3.43-1 +- Upgrade to latest from NSA + * Merged seuser parser resync, dbase tracking and cleanup, strtol + bug, copyright, and assert space patches from Ivan Gyurdiev. + * Added src/*_internal.h in preparation for other changes. + * Added hidden/hidden_proto/hidden_def to src/debug.[hc] and + src/seusers.[hc]. + + +* Thu Nov 3 2005 Dan Walsh 1.3.41-1 +- Upgrade to latest from NSA + * 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. + * Merged install seusers, handle/error messages, MLS parsing, + and seusers validation patches from Ivan Gyurdiev. + +* Mon Oct 31 2005 Dan Walsh 1.3.39-1 +- Upgrade to latest from NSA + * Merged record interface, dbase flush, common database code, + and record bugfix patches from Ivan Gyurdiev. + +* Fri Oct 28 2005 Dan Walsh 1.3.38-1 +- Upgrade to latest from NSA + * Merged dbase policydb list and count change from Ivan Gyurdiev. + * Merged enable dbase and set relay patches from Ivan Gyurdiev. + +* Thu Oct 27 2005 Dan Walsh 1.3.36-1 +- Update from NSA + * Merged query APIs and dbase_file_set patches from Ivan Gyurdiev. + +* Wed Oct 26 2005 Dan Walsh 1.3.35-1 +- Update from NSA + * Merged sepol handle passing, seusers support, and policydb cache + patches from Ivan Gyurdiev. + +* Tue Oct 25 2005 Dan Walsh 1.3.34-1 +- Update from NSA + * Merged resync to sepol changes and booleans fixes/improvements + patches from Ivan Gyurdiev. + * Merged support for genhomedircon/homedir template, store selection, + explicit policy reload, and semanage.conf relocation from Joshua + Brindle. + +* Mon Oct 24 2005 Dan Walsh 1.3.32-1 +- Update from NSA + * Merged resync to sepol changes and transaction fix patches from + Ivan Gyurdiev. + * Merged reorganize users patch from Ivan Gyurdiev. + * Merged remove unused relay functions patch from Ivan Gyurdiev. + +* Fri Oct 21 2005 Dan Walsh 1.3.30-1 +- Update from NSA + * Fixed policy file leaks in semanage_load_module and + semanage_write_module. + * Merged further database work from Ivan Gyurdiev. + * Fixed bug in semanage_direct_disconnect. + +* Thu Oct 20 2005 Dan Walsh 1.3.28-1 +- Update from NSA + * Merged interface renaming patch from Ivan Gyurdiev. + * Merged policy component patch from Ivan Gyurdiev. + * 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. + * 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. + * Merged fixes for make DESTDIR= builds from Joshua Brindle. + +* Tue Oct 18 2005 Dan Walsh 1.3.24-1 +- Update from NSA + * 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. + * Changed default args for load_policy to be null, as it no longer + takes a pathname argument and we want to preserve booleans. + * 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. + * 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. + + +* Tue Oct 18 2005 Dan Walsh 1.3.20-1 +- Update from NSA + * Changed default args for load_policy to be null, as it no longer + takes a pathname argument and we want to preserve booleans. + * 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. + * 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. + +* Tue Oct 18 2005 Dan Walsh 1.3.20-1 +- Update from NSA + * Merged user and port APIs - policy database patch from Ivan + Gyurdiev. + * 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. + +* Sat Oct 15 2005 Dan Walsh 1.3.18-1 +- Update from NSA + * Merged bugfix patch from Ivan Gyurdiev. + * Merged seuser database patch from Ivan Gyurdiev. + Merged direct user/port databases to the handle from Ivan Gyurdiev. + * Removed obsolete include/semanage/commit_api.h (leftover). + Merged seuser record patch from Ivan Gyurdiev. + * Merged boolean and interface databases from Ivan Gyurdiev. + +* Fri Oct 14 2005 Dan Walsh 1.3.14-1 +- Update from NSA + * Updated to use get interfaces for hidden sepol_module_package type. + * 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. + * Merged new callback-based error reporting system and ongoing + database work from Ivan Gyurdiev. + +* Wed Oct 12 2005 Dan Walsh 1.3.11-1 +- Update from NSA + * 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(). + +* Mon Oct 10 2005 Dan Walsh 1.3.10-1 +- Update from NSA + * Updated for changes to libsepol, and to only use types and interfaces + provided by the shared libsepol. + +* Fri Oct 7 2005 Dan Walsh 1.3.9-1 +- Update from NSA + * Merged further database work from Ivan Gyurdiev. + +* Tue Oct 4 2005 Dan Walsh 1.3.8-1 +- Update from NSA + * Merged iterate, redistribute, and dbase split patches from + Ivan Gyurdiev. + +* Mon Oct 3 2005 Dan Walsh 1.3.7-1 +- Update from NSA + * Merged patch series from Ivan Gyurdiev. + (pointer typedef elimination, file renames, dbase work, backend + separation) + * 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. + +* Wed Sep 28 2005 Dan Walsh 1.3.5-1 +- Update from NSA + * 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. + +* Fri Sep 23 2005 Dan Walsh 1.3.4-1 +- Update from NSA + * Merged dbase redesign patch from Ivan Gyurdiev. + +* Wed Sep 21 2005 Dan Walsh 1.3.3-1 +- Update from NSA + * Merged boolean record, stub record handler, and status codes + patches from Ivan Gyurdiev. + +* Tue Sep 20 2005 Dan Walsh 1.3.2-1 +- Update from NSA + * Merged stub iterator functionality from Ivan Gyurdiev. + * Merged interface record patch from Ivan Gyurdiev. + +* Wed Sep 14 2005 Dan Walsh 1.3.1-1 +- Update from NSA + * Merged stub functionality for managing user and port records, + and record table code from Ivan Gyurdiev. + * Updated version for release. + +* Thu Sep 1 2005 Dan Walsh 1.1.6-1 +- Update from NSA + * Merged semod.conf template patch from Dan Walsh (Red Hat), + but restored location to /usr/share/semod/semod.conf. + * Fixed several bugs found by valgrind. + * Fixed bug in prior patch for the semod_build_module_list leak. + * 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. + +* Thu Aug 25 2005 Dan Walsh 1.1.3-1 +- Update from NSA + * 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. + * Merged several fixes from Serge Hallyn (IBM). Bugs found by + Coverity. + * Fixed several other bugs and warnings. + * Merged patch to move module read/write code from libsemanage + to libsepol from Jason Tang (Tresys). + * Merged relay records patch from Ivan Gyurdiev. + * Merged key extract patch from Ivan Gyurdiev. + +- Initial version +- Created by Stephen Smalley diff --git a/SPECS/semanage.conf b/SPECS/semanage.conf new file mode 100644 index 0000000..9045021 --- /dev/null +++ b/SPECS/semanage.conf @@ -0,0 +1,57 @@ +# Authors: Jason Tang +# +# 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 . Change this setting if a different +# version is necessary. +#policy-version = 19 + +# expand-check check neverallow rules when executing all semanage +# commands. There might be a penalty in execution time if this +# option is enabled. +expand-check=0 + +# usepasswd check tells semanage to scan all pass word records for home directories +# and setup the labeling correctly. If this is turned off, SELinux will label /home +# correctly only. You will need to use semanage fcontext command. +# For example, if you had home dirs in /althome directory you would have to execute +# semanage fcontext -a -e /home /althome +usepasswd=False +bzip-small=true +bzip-blocksize=5 +ignoredirs=/root + +[sefcontext_compile] +path = /usr/sbin/sefcontext_compile +args = -r $@ +[end] diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..8c26915 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2.9 diff --git a/example/test_fcontext.c b/example/test_fcontext.c new file mode 100644 index 0000000..c2ffcab --- /dev/null +++ b/example/test_fcontext.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include +#include +#include + +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/include/Makefile b/include/Makefile new file mode 100644 index 0000000..6e44a28 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,12 @@ +# Installation directories. +PREFIX ?= /usr +INCDIR ?= $(PREFIX)/include/semanage + +all: + +install: all + test -d $(DESTDIR)$(INCDIR) || install -m 755 -d $(DESTDIR)$(INCDIR) + install -m 644 $(wildcard semanage/*.h) $(DESTDIR)$(INCDIR) + +indent: + ../../scripts/Lindent $(wildcard semanage/*.h) diff --git a/include/semanage/boolean_record.h b/include/semanage/boolean_record.h new file mode 100644 index 0000000..b618593 --- /dev/null +++ b/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 + +#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/include/semanage/booleans_active.h b/include/semanage/booleans_active.h new file mode 100644 index 0000000..0bbe51b --- /dev/null +++ b/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 +#include + +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/include/semanage/booleans_local.h b/include/semanage/booleans_local.h new file mode 100644 index 0000000..a32e98c --- /dev/null +++ b/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 +#include + +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/include/semanage/booleans_policy.h b/include/semanage/booleans_policy.h new file mode 100644 index 0000000..08d0bbb --- /dev/null +++ b/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 +#include + +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/include/semanage/context_record.h b/include/semanage/context_record.h new file mode 100644 index 0000000..54dcea5 --- /dev/null +++ b/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 + +#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/include/semanage/debug.h b/include/semanage/debug.h new file mode 100644 index 0000000..effc24a --- /dev/null +++ b/include/semanage/debug.h @@ -0,0 +1,54 @@ +/* Author: Joshua Brindle + * Jason Tang + * Ivan Gyurdiev + * + * 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 + +#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/include/semanage/fcontext_record.h b/include/semanage/fcontext_record.h new file mode 100644 index 0000000..4cf9261 --- /dev/null +++ b/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 +#include + +#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/include/semanage/fcontexts_local.h b/include/semanage/fcontexts_local.h new file mode 100644 index 0000000..aaecc0f --- /dev/null +++ b/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 +#include + +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/include/semanage/fcontexts_policy.h b/include/semanage/fcontexts_policy.h new file mode 100644 index 0000000..199a1e1 --- /dev/null +++ b/include/semanage/fcontexts_policy.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_FCONTEXTS_POLICY_H_ +#define _SEMANAGE_FCONTEXTS_POLICY_H_ + +#include +#include + +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); + +extern int semanage_fcontext_list_homedirs(semanage_handle_t * handle, + semanage_fcontext_t *** records, + unsigned int *count); + +#endif diff --git a/include/semanage/handle.h b/include/semanage/handle.h new file mode 100644 index 0000000..c816590 --- /dev/null +++ b/include/semanage/handle.h @@ -0,0 +1,172 @@ +/* Authors: Joshua Brindle + * Jason Tang + * + * 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 + +/* 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/include/semanage/ibendport_record.h b/include/semanage/ibendport_record.h new file mode 100644 index 0000000..153eea0 --- /dev/null +++ b/include/semanage/ibendport_record.h @@ -0,0 +1,62 @@ +/*Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_IBENDPORT_RECORD_H_ +#define _SEMANAGE_IBENDPORT_RECORD_H_ + +#include +#include +#include + +#ifndef _SEMANAGE_IBENDPORT_DEFINED_ +struct semanage_ibendport; +struct semanage_ibendport_key; +typedef struct semanage_ibendport semanage_ibendport_t; +typedef struct semanage_ibendport_key semanage_ibendport_key_t; +#define _SEMANAGE_IBENDPORT_DEFINED_ +#endif + +extern int semanage_ibendport_compare(const semanage_ibendport_t *ibendport, + const semanage_ibendport_key_t *key); + +extern int semanage_ibendport_compare2(const semanage_ibendport_t *ibendport, + const semanage_ibendport_t *ibendport2); + +extern int semanage_ibendport_key_create(semanage_handle_t *handle, + const char *ibdev_name, + int port, + semanage_ibendport_key_t **key_ptr); + +extern int semanage_ibendport_key_extract(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + semanage_ibendport_key_t **key_ptr); + +extern void semanage_ibendport_key_free(semanage_ibendport_key_t *key); + +extern int semanage_ibendport_get_ibdev_name(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + char **ibdev_name_ptr); + +extern int semanage_ibendport_set_ibdev_name(semanage_handle_t *handle, + semanage_ibendport_t *ibendport, + const char *ibdev_name); + +extern int semanage_ibendport_get_port(const semanage_ibendport_t *ibendport); + +extern void semanage_ibendport_set_port(semanage_ibendport_t *ibendport, int port); + +extern semanage_context_t *semanage_ibendport_get_con(const semanage_ibendport_t *ibendport); + +extern int semanage_ibendport_set_con(semanage_handle_t *handle, + semanage_ibendport_t *ibendport, + semanage_context_t *con); + +extern int semanage_ibendport_create(semanage_handle_t *handle, + semanage_ibendport_t **ibendport_ptr); + +extern int semanage_ibendport_clone(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + semanage_ibendport_t **ibendport_ptr); + +extern void semanage_ibendport_free(semanage_ibendport_t *ibendport); + +#endif diff --git a/include/semanage/ibendports_local.h b/include/semanage/ibendports_local.h new file mode 100644 index 0000000..641dd35 --- /dev/null +++ b/include/semanage/ibendports_local.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc */ + +#ifndef _SEMANAGE_IBENDPORTS_LOCAL_H_ +#define _SEMANAGE_IBENDPORTS_LOCAL_H_ + +#include +#include + +extern int semanage_ibendport_modify_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + const semanage_ibendport_t *data); + +extern int semanage_ibendport_del_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key); + +extern int semanage_ibendport_query_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + semanage_ibendport_t **response); + +extern int semanage_ibendport_exists_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + int *response); + +extern int semanage_ibendport_count_local(semanage_handle_t *handle, + unsigned int *response); + +extern int semanage_ibendport_iterate_local(semanage_handle_t *handle, + int (*handler)(const semanage_ibendport_t *record, + void *varg), + void *handler_arg); + +extern int semanage_ibendport_list_local(semanage_handle_t *handle, + semanage_ibendport_t ***records, + unsigned int *count); + +#endif diff --git a/include/semanage/ibendports_policy.h b/include/semanage/ibendports_policy.h new file mode 100644 index 0000000..3fc1976 --- /dev/null +++ b/include/semanage/ibendports_policy.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2017 Mellanox Techonologies Inc */ + +#ifndef _SEMANAGE_IBENDPORTS_POLICY_H_ +#define _SEMANAGE_IBENDPORTS_POLICY_H_ + +#include +#include + +extern int semanage_ibendport_query(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + semanage_ibendport_t **response); + +extern int semanage_ibendport_exists(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, int *response); + +extern int semanage_ibendport_count(semanage_handle_t *handle, + unsigned int *response); + +extern int semanage_ibendport_iterate(semanage_handle_t *handle, + int (*handler)(const semanage_ibendport_t *record, + void *varg), + void *handler_arg); + +extern int semanage_ibendport_list(semanage_handle_t *handle, + semanage_ibendport_t ***records, + unsigned int *count); + +#endif diff --git a/include/semanage/ibpkey_record.h b/include/semanage/ibpkey_record.h new file mode 100644 index 0000000..9da7dc5 --- /dev/null +++ b/include/semanage/ibpkey_record.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc */ + +#ifndef _SEMANAGE_IBPKEY_RECORD_H_ +#define _SEMANAGE_IBPKEY_RECORD_H_ + +#include +#include +#include +#include + +#ifndef _SEMANAGE_IBPKEY_DEFINED_ +struct semanage_ibpkey; +struct semanage_ibpkey_key; +typedef struct semanage_ibpkey semanage_ibpkey_t; +typedef struct semanage_ibpkey_key semanage_ibpkey_key_t; +#define _SEMANAGE_IBPKEY_DEFINED_ +#endif + +extern int semanage_ibpkey_compare(const semanage_ibpkey_t *ibpkey, + const semanage_ibpkey_key_t *key); + +extern int semanage_ibpkey_compare2(const semanage_ibpkey_t *ibpkey, + const semanage_ibpkey_t *ibpkey2); + +extern int semanage_ibpkey_key_create(semanage_handle_t *handle, + const char *subnet_prefix, + int low, int high, + semanage_ibpkey_key_t **key_ptr); + +extern int semanage_ibpkey_key_extract(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + semanage_ibpkey_key_t **key_ptr); + +extern void semanage_ibpkey_key_free(semanage_ibpkey_key_t *key); + +extern int semanage_ibpkey_get_subnet_prefix(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + char **subnet_prefix_ptr); + +extern uint64_t semanage_ibpkey_get_subnet_prefix_bytes(const semanage_ibpkey_t *ibpkey); + +extern int semanage_ibpkey_set_subnet_prefix(semanage_handle_t *handle, + semanage_ibpkey_t *ibpkey, + const char *subnet_prefix); + +extern void semanage_ibpkey_set_subnet_prefix_bytes(semanage_ibpkey_t *ibpkey, + uint64_t subnet_prefix); + +extern int semanage_ibpkey_get_low(const semanage_ibpkey_t *ibpkey); + +extern int semanage_ibpkey_get_high(const semanage_ibpkey_t *ibpkey); + +extern void semanage_ibpkey_set_pkey(semanage_ibpkey_t *ibpkey, int pkey_num); + +extern void semanage_ibpkey_set_range(semanage_ibpkey_t *ibpkey, int low, int high); + +extern semanage_context_t *semanage_ibpkey_get_con(const semanage_ibpkey_t *ibpkey); + +extern int semanage_ibpkey_set_con(semanage_handle_t *handle, + semanage_ibpkey_t *ibpkey, + semanage_context_t *con); + +extern int semanage_ibpkey_create(semanage_handle_t *handle, + semanage_ibpkey_t **ibpkey_ptr); + +extern int semanage_ibpkey_clone(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + semanage_ibpkey_t **ibpkey_ptr); + +extern void semanage_ibpkey_free(semanage_ibpkey_t *ibpkey); + +#endif diff --git a/include/semanage/ibpkeys_local.h b/include/semanage/ibpkeys_local.h new file mode 100644 index 0000000..079a642 --- /dev/null +++ b/include/semanage/ibpkeys_local.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc */ + +#ifndef _SEMANAGE_IBPKEYS_LOCAL_H_ +#define _SEMANAGE_IBPKEYS_LOCAL_H_ + +#include +#include + +extern int semanage_ibpkey_modify_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + const semanage_ibpkey_t *data); + +extern int semanage_ibpkey_del_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key); + +extern int semanage_ibpkey_query_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + semanage_ibpkey_t **response); + +extern int semanage_ibpkey_exists_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + int *response); + +extern int semanage_ibpkey_count_local(semanage_handle_t *handle, + unsigned int *response); + +extern int semanage_ibpkey_iterate_local(semanage_handle_t *handle, + int (*handler)(const semanage_ibpkey_t * + record, void *varg), + void *handler_arg); + +extern int semanage_ibpkey_list_local(semanage_handle_t *handle, + semanage_ibpkey_t ***records, + unsigned int *count); + +#endif diff --git a/include/semanage/ibpkeys_policy.h b/include/semanage/ibpkeys_policy.h new file mode 100644 index 0000000..c287ac0 --- /dev/null +++ b/include/semanage/ibpkeys_policy.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2017 Mellanox Technolgies Inc. */ + +#ifndef _SEMANAGE_IBPKEYS_POLICY_H_ +#define _SEMANAGE_IBPKEYS_POLICY_H_ + +#include +#include + +extern int semanage_ibpkey_query(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + semanage_ibpkey_t **response); + +extern int semanage_ibpkey_exists(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, int *response); + +extern int semanage_ibpkey_count(semanage_handle_t *handle, + unsigned int *response); + +extern int semanage_ibpkey_iterate(semanage_handle_t *handle, + int (*handler)(const semanage_ibpkey_t *record, + void *varg), + void *handler_arg); + +extern int semanage_ibpkey_list(semanage_handle_t *handle, + semanage_ibpkey_t ***records, + unsigned int *count); + +#endif diff --git a/include/semanage/iface_record.h b/include/semanage/iface_record.h new file mode 100644 index 0000000..857d42e --- /dev/null +++ b/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 +#include + +#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/include/semanage/interfaces_local.h b/include/semanage/interfaces_local.h new file mode 100644 index 0000000..9b07ca6 --- /dev/null +++ b/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 +#include + +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/include/semanage/interfaces_policy.h b/include/semanage/interfaces_policy.h new file mode 100644 index 0000000..9816280 --- /dev/null +++ b/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 +#include + +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/include/semanage/modules.h b/include/semanage/modules.h new file mode 100644 index 0000000..4b93e54 --- /dev/null +++ b/include/semanage/modules.h @@ -0,0 +1,285 @@ +/* Authors: Joshua Brindle + * Jason Tang + * + * 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 +#include +#include +#include + +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/include/semanage/node_record.h b/include/semanage/node_record.h new file mode 100644 index 0000000..c9e4ce8 --- /dev/null +++ b/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 +#include +#include + +#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/include/semanage/nodes_local.h b/include/semanage/nodes_local.h new file mode 100644 index 0000000..07ffd97 --- /dev/null +++ b/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 +#include + +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/include/semanage/nodes_policy.h b/include/semanage/nodes_policy.h new file mode 100644 index 0000000..9150dfc --- /dev/null +++ b/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 +#include + +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/include/semanage/port_record.h b/include/semanage/port_record.h new file mode 100644 index 0000000..7107480 --- /dev/null +++ b/include/semanage/port_record.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#ifndef _SEMANAGE_PORT_RECORD_H_ +#define _SEMANAGE_PORT_RECORD_H_ + +#include +#include + +#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 +#define SEMANAGE_PROTO_DCCP 2 +#define SEMANAGE_PROTO_SCTP 3 + +/* 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/include/semanage/ports_local.h b/include/semanage/ports_local.h new file mode 100644 index 0000000..47cba44 --- /dev/null +++ b/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 +#include + +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/include/semanage/ports_policy.h b/include/semanage/ports_policy.h new file mode 100644 index 0000000..364bce8 --- /dev/null +++ b/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 +#include + +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/include/semanage/semanage.h b/include/semanage/semanage.h new file mode 100644 index 0000000..0489014 --- /dev/null +++ b/include/semanage/semanage.h @@ -0,0 +1,61 @@ +/* Authors: Joshua Brindle + * Jason Tang + * + * 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 +#include +#include + +/* Records */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Dbase */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/include/semanage/seuser_record.h b/include/semanage/seuser_record.h new file mode 100644 index 0000000..bf0dc8e --- /dev/null +++ b/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 + +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/include/semanage/seusers_local.h b/include/semanage/seusers_local.h new file mode 100644 index 0000000..4333a7b --- /dev/null +++ b/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 +#include + +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/include/semanage/seusers_policy.h b/include/semanage/seusers_policy.h new file mode 100644 index 0000000..8d39d45 --- /dev/null +++ b/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 +#include + +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/include/semanage/user_record.h b/include/semanage/user_record.h new file mode 100644 index 0000000..d4a4866 --- /dev/null +++ b/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 +#include + +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/include/semanage/users_local.h b/include/semanage/users_local.h new file mode 100644 index 0000000..952474c --- /dev/null +++ b/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 +#include + +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/include/semanage/users_policy.h b/include/semanage/users_policy.h new file mode 100644 index 0000000..b1677ec --- /dev/null +++ b/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 +#include + +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/man/Makefile b/man/Makefile new file mode 100644 index 0000000..f626447 --- /dev/null +++ b/man/Makefile @@ -0,0 +1,26 @@ +# Installation directories. +LINGUAS ?= ru +PREFIX ?= /usr +MANDIR ?= $(PREFIX)/share/man +MAN3SUBDIR ?= man3 +MAN5SUBDIR ?= man5 +MAN3DIR ?= $(MANDIR)/$(MAN3SUBDIR) +MAN5DIR ?= $(MANDIR)/$(MAN5SUBDIR) + +all: + +install: all + mkdir -p $(DESTDIR)$(MAN3DIR) + mkdir -p $(DESTDIR)$(MAN5DIR) + install -m 644 man3/*.3 $(DESTDIR)$(MAN3DIR) + install -m 644 man5/*.5 $(DESTDIR)$(MAN5DIR) + for lang in $(LINGUAS) ; do \ + if [ -e $${lang}/man3 ] ; then \ + mkdir -p $(DESTDIR)$(MANDIR)/$${lang}/$(MAN3SUBDIR) ; \ + install -m 644 $${lang}/man3/*.3 $(DESTDIR)$(MANDIR)/$${lang}/$(MAN3SUBDIR) ; \ + fi ; \ + if [ -e $${lang}/man5 ] ; then \ + mkdir -p $(DESTDIR)$(MANDIR)/$${lang}/$(MAN5SUBDIR) ; \ + install -m 644 $${lang}/man5/*.5 $(DESTDIR)$(MANDIR)/$${lang}/$(MAN5SUBDIR) ; \ + fi ; \ + done diff --git a/man/man3/semanage_bool.3 b/man/man3/semanage_bool.3 new file mode 100644 index 0000000..67da632 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_bool_count.3 b/man/man3/semanage_bool_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_bool_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_bool_count_active.3 b/man/man3/semanage_bool_count_active.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_bool_count_active.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_bool_count_local.3 b/man/man3/semanage_bool_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_bool_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_bool_del_local.3 b/man/man3/semanage_bool_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_bool_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_bool_exists.3 b/man/man3/semanage_bool_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_bool_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_bool_exists_active.3 b/man/man3/semanage_bool_exists_active.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_bool_exists_active.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_bool_exists_local.3 b/man/man3/semanage_bool_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_bool_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_bool_iterate.3 b/man/man3/semanage_bool_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_bool_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_bool_iterate_active.3 b/man/man3/semanage_bool_iterate_active.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_bool_iterate_active.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_bool_iterate_local.3 b/man/man3/semanage_bool_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_bool_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_bool_list.3 b/man/man3/semanage_bool_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_bool_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_bool_list_active.3 b/man/man3/semanage_bool_list_active.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_bool_list_active.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_bool_list_local.3 b/man/man3/semanage_bool_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_bool_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_bool_modify_local.3 b/man/man3/semanage_bool_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_bool_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_bool_query.3 b/man/man3/semanage_bool_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_bool_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_bool_query_active.3 b/man/man3/semanage_bool_query_active.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_bool_query_active.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_bool_query_local.3 b/man/man3/semanage_bool_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_bool_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_bool_set_active.3 b/man/man3/semanage_bool_set_active.3 new file mode 100644 index 0000000..d868fe8 --- /dev/null +++ b/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 +.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/man/man3/semanage_count.3 b/man/man3/semanage_count.3 new file mode 100644 index 0000000..6ff89be --- /dev/null +++ b/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 pointed 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/man/man3/semanage_del.3 b/man/man3/semanage_del.3 new file mode 100644 index 0000000..4dd0a77 --- /dev/null +++ b/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/man/man3/semanage_exists.3 b/man/man3/semanage_exists.3 new file mode 100644 index 0000000..6d68c76 --- /dev/null +++ b/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/man/man3/semanage_fcontext.3 b/man/man3/semanage_fcontext.3 new file mode 100644 index 0000000..1f0bf32 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_fcontext_count.3 b/man/man3/semanage_fcontext_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_fcontext_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_fcontext_count_local.3 b/man/man3/semanage_fcontext_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_fcontext_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_fcontext_del_local.3 b/man/man3/semanage_fcontext_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_fcontext_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_fcontext_exists.3 b/man/man3/semanage_fcontext_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_fcontext_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_fcontext_exists_local.3 b/man/man3/semanage_fcontext_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_fcontext_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_fcontext_iterate.3 b/man/man3/semanage_fcontext_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_fcontext_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_fcontext_iterate_local.3 b/man/man3/semanage_fcontext_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_fcontext_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_fcontext_list.3 b/man/man3/semanage_fcontext_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_fcontext_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_fcontext_list_local.3 b/man/man3/semanage_fcontext_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_fcontext_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_fcontext_modify_local.3 b/man/man3/semanage_fcontext_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_fcontext_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_fcontext_query.3 b/man/man3/semanage_fcontext_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_fcontext_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_fcontext_query_local.3 b/man/man3/semanage_fcontext_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_fcontext_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_iface.3 b/man/man3/semanage_iface.3 new file mode 100644 index 0000000..90af8b4 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_iface_count.3 b/man/man3/semanage_iface_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_iface_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_iface_count_local.3 b/man/man3/semanage_iface_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_iface_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_iface_del_local.3 b/man/man3/semanage_iface_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_iface_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_iface_exists.3 b/man/man3/semanage_iface_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_iface_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_iface_exists_local.3 b/man/man3/semanage_iface_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_iface_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_iface_iterate.3 b/man/man3/semanage_iface_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_iface_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_iface_iterate_local.3 b/man/man3/semanage_iface_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_iface_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_iface_list.3 b/man/man3/semanage_iface_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_iface_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_iface_list_local.3 b/man/man3/semanage_iface_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_iface_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_iface_modify_local.3 b/man/man3/semanage_iface_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_iface_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_iface_query.3 b/man/man3/semanage_iface_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_iface_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_iface_query_local.3 b/man/man3/semanage_iface_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_iface_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_iterate.3 b/man/man3/semanage_iterate.3 new file mode 100644 index 0000000..1528164 --- /dev/null +++ b/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/man/man3/semanage_list.3 b/man/man3/semanage_list.3 new file mode 100644 index 0000000..0e1ca7b --- /dev/null +++ b/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 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/man/man3/semanage_modify.3 b/man/man3/semanage_modify.3 new file mode 100644 index 0000000..ee23900 --- /dev/null +++ b/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/man/man3/semanage_node.3 b/man/man3/semanage_node.3 new file mode 100644 index 0000000..2df7a91 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_node_count.3 b/man/man3/semanage_node_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_node_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_node_count_local.3 b/man/man3/semanage_node_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_node_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_node_del_local.3 b/man/man3/semanage_node_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_node_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_node_exists.3 b/man/man3/semanage_node_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_node_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_node_exists_local.3 b/man/man3/semanage_node_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_node_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_node_iterate.3 b/man/man3/semanage_node_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_node_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_node_iterate_local.3 b/man/man3/semanage_node_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_node_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_node_list.3 b/man/man3/semanage_node_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_node_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_node_list_local.3 b/man/man3/semanage_node_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_node_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_node_modify_local.3 b/man/man3/semanage_node_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_node_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_node_query.3 b/man/man3/semanage_node_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_node_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_node_query_local.3 b/man/man3/semanage_node_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_node_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_port.3 b/man/man3/semanage_port.3 new file mode 100644 index 0000000..3a4e626 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_port_count.3 b/man/man3/semanage_port_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_port_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_port_count_local.3 b/man/man3/semanage_port_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_port_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_port_del_local.3 b/man/man3/semanage_port_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_port_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_port_exists.3 b/man/man3/semanage_port_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_port_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_port_exists_local.3 b/man/man3/semanage_port_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_port_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_port_iterate.3 b/man/man3/semanage_port_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_port_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_port_iterate_local.3 b/man/man3/semanage_port_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_port_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_port_list.3 b/man/man3/semanage_port_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_port_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_port_list_local.3 b/man/man3/semanage_port_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_port_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_port_modify_local.3 b/man/man3/semanage_port_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_port_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_port_query.3 b/man/man3/semanage_port_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_port_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_port_query_local.3 b/man/man3/semanage_port_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_port_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_query.3 b/man/man3/semanage_query.3 new file mode 100644 index 0000000..e61c8b8 --- /dev/null +++ b/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/man/man3/semanage_set_root.3 b/man/man3/semanage_set_root.3 new file mode 100644 index 0000000..8125416 --- /dev/null +++ b/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 + +.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/man/man3/semanage_seuser.3 b/man/man3/semanage_seuser.3 new file mode 100644 index 0000000..be0fa68 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_seuser_count.3 b/man/man3/semanage_seuser_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_seuser_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_seuser_count_local.3 b/man/man3/semanage_seuser_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_seuser_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_seuser_del_local.3 b/man/man3/semanage_seuser_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_seuser_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_seuser_exists.3 b/man/man3/semanage_seuser_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_seuser_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_seuser_exists_local.3 b/man/man3/semanage_seuser_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_seuser_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_seuser_iterate.3 b/man/man3/semanage_seuser_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_seuser_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_seuser_iterate_local.3 b/man/man3/semanage_seuser_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_seuser_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_seuser_list.3 b/man/man3/semanage_seuser_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_seuser_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_seuser_list_local.3 b/man/man3/semanage_seuser_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_seuser_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_seuser_modify_local.3 b/man/man3/semanage_seuser_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_seuser_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_seuser_query.3 b/man/man3/semanage_seuser_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_seuser_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_seuser_query_local.3 b/man/man3/semanage_seuser_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_seuser_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_user.3 b/man/man3/semanage_user.3 new file mode 100644 index 0000000..6102dd5 --- /dev/null +++ b/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 +.br +.B #include +.br +.B #include + +.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/man/man3/semanage_user_count.3 b/man/man3/semanage_user_count.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_user_count.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_user_count_local.3 b/man/man3/semanage_user_count_local.3 new file mode 100644 index 0000000..7478bc2 --- /dev/null +++ b/man/man3/semanage_user_count_local.3 @@ -0,0 +1 @@ +.so man3/semanage_count.3 diff --git a/man/man3/semanage_user_del_local.3 b/man/man3/semanage_user_del_local.3 new file mode 100644 index 0000000..a01dfcd --- /dev/null +++ b/man/man3/semanage_user_del_local.3 @@ -0,0 +1 @@ +.so man3/semanage_del.3 diff --git a/man/man3/semanage_user_exists.3 b/man/man3/semanage_user_exists.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_user_exists.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_user_exists_local.3 b/man/man3/semanage_user_exists_local.3 new file mode 100644 index 0000000..40f3406 --- /dev/null +++ b/man/man3/semanage_user_exists_local.3 @@ -0,0 +1 @@ +.so man3/semanage_exists.3 diff --git a/man/man3/semanage_user_iterate.3 b/man/man3/semanage_user_iterate.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_user_iterate.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_user_iterate_local.3 b/man/man3/semanage_user_iterate_local.3 new file mode 100644 index 0000000..7fc9c3d --- /dev/null +++ b/man/man3/semanage_user_iterate_local.3 @@ -0,0 +1 @@ +.so man3/semanage_iterate.3 diff --git a/man/man3/semanage_user_list.3 b/man/man3/semanage_user_list.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_user_list.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_user_list_local.3 b/man/man3/semanage_user_list_local.3 new file mode 100644 index 0000000..b7095f8 --- /dev/null +++ b/man/man3/semanage_user_list_local.3 @@ -0,0 +1 @@ +.so man3/semanage_list.3 diff --git a/man/man3/semanage_user_modify_local.3 b/man/man3/semanage_user_modify_local.3 new file mode 100644 index 0000000..3a07fe8 --- /dev/null +++ b/man/man3/semanage_user_modify_local.3 @@ -0,0 +1 @@ +.so man3/semanage_modify.3 diff --git a/man/man3/semanage_user_query.3 b/man/man3/semanage_user_query.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_user_query.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man3/semanage_user_query_local.3 b/man/man3/semanage_user_query_local.3 new file mode 100644 index 0000000..5b5c844 --- /dev/null +++ b/man/man3/semanage_user_query_local.3 @@ -0,0 +1 @@ +.so man3/semanage_query.3 diff --git a/man/man5/semanage.conf.5 b/man/man5/semanage.conf.5 new file mode 100644 index 0000000..8f8de55 --- /dev/null +++ b/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 . 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 . + +The SELinux management library was written by Tresys Technology LLC and Red Hat Inc. diff --git a/man/ru/man5/semanage.conf.5 b/man/ru/man5/semanage.conf.5 new file mode 100644 index 0000000..cf65b3e --- /dev/null +++ b/man/ru/man5/semanage.conf.5 @@ -0,0 +1,117 @@ +.TH semanage.conf "5" "Сентябрь 2011" "semanage.conf" "Администрирование системы Linux" +.SH ИМЯ +semanage.conf \- глобальный файл конфигурации для библиотеки управления SELinux +.SH ОПИСАНИЕ +.PP +Файл +.BR semanage.conf +обычно располагается в каталоге /etc/selinux и используется для конфигурации поведения библиотеки управления SELinux в среде выполнения. + +.PP +Каждая строка должна содержать параметр конфигурации, за которым следует знак равенства ("=") и значение конфигурации этого параметра. Все символы, которые следуют за "#", игнорируются (аналогично пустым строкам). + +.PP +Разрешены следующие параметры: + +.RS +.TP +.B module-store +Указать, как библиотека управления SELinux должна взаимодействовать с хранилищем политики SELinux. Если установлено "direct", библиотека управления SELinux выполняет запись напрямую в хранилище модулей политики SELinux (это значение по умолчанию). +В ином случае в качестве аргумента может использоваться путь к сокету или имя сервера. +Если аргумент начинается с "/" (как в "/foo/bar"), он представляет собой путь к именованному сокету, который следует использовать для подключения сервера управления политикой. +Если аргумент не начинается с "/" (как в "foo.com:4242"), он должен интерпретироваться как имя удалённого сервера управления политикой, который следует использовать через TCP-подключение (порт по умолчанию 4242, если только после имени сервера через двоеточие, разделяющее два поля, не указан другой порт). + +.TP +.B root +Указать альтернативный корневой путь к хранилищу. По умолчанию: "/" + +.TP +.B store-root +Указать альтернативный путь store_root. По умолчанию: "/var/lib/selinux" + +.TP +.B compiler-directory +Указать альтернативный каталог, который содержит компиляторы HLL в CIL. Значение по умолчанию: "/usr/libexec/selinux/hll". + +.TP +.B ignore-module-cache +Определяет, следует ли игнорировать кэш модулей CIL, скомпилированных из HLL. Можно установить либо значение "true", либо значение "false" (по умолчанию установлено "false"). +Если кэш игнорируется, все модули CIL перекомпилируются из соответствующих модулей HLL. + +.TP +.B policy-version +При создании политики +.BR semanage +по умолчанию устанавливает версию политики POLICYDB_VERSION_MAX, как определено в . Измените этот параметр, если для политики требуется установить другую версию. + +.TP +.B target-platform +Целевая платформа, для которой создаются политики. Действительными значениями являются "selinux" и "xen" (по умолчанию установлено "selinux"). + +.TP +.B expand-check +Определяет, следует ли проверять правила "neverallow" при исполнении всех команд +.BR semanage. +Для этого параметра можно установить либо значение "0" (отключён), либо "1" (включён). По умолчанию параметр включён. Время выполнения может сильно возрасти, если этот параметр включён. + +.TP +.B file-mode +По умолчанию для разрешительного режима для файлов среды выполнения политики установлено значение 0644. + +.TP +.B save-previous +Определяет, следует ли сохранять прежний каталог модуля после успешной фиксации модуля в хранилище политики. Для параметра можно установить либо значение "true", либо значение "false". По умолчанию установлено "false" (прежняя версия удаляется). + +.TP +.B save-linked +Определяет, следует ли сохранять прежний связанный модуль (с именем "base.linked") после успешной фиксации модуля в хранилище политики. +Для параметра можно установить либо значение "true", либо значение "false". По умолчанию установлено "false" (прежний модуль удаляется). + +.TP +.B ignoredirs +Разделённый ";" список каталогов, которые следует игнорировать при установке домашних каталогов пользователей. +В некоторых дистрибутивах этот параметр используется для того, чтобы /root не отмечался как домашний каталог. + +.TP +.B usepasswd +Определяет, использовать ли getpwent(), чтобы получить список домашних каталогов, для которых следует проставить метки. Для параметра можно установить либо значение "true", либо значение "false" (по умолчанию установлено "true"). + +.TP +.B disable-genhomedircon +Определяет, следует ли исполнять функцию genhomedircon при использовании команды +.BR semanage. +Для параметра можно установить либо значение "true", либо значение "false". По умолчанию возможность genhomedircon включена (эквивалентно установке значения "false" для этого параметра). + +.TP +.B handle-unknown +Этот параметр управляет тем, как ядро обрабатывает разрешения, которые определены в ядре, но отсутствуют в фактической политике. +Возможные значения: "deny", "reject" или "allow". + +.TP +.B bzip-blocksize +Этот параметр должен находиться в диапазоне 0-9. Значение 0 означает отсутствие сжатия. По умолчанию значение размера блока bzip равняется 9 (фактическое значение размера блока получается путём умножения на 100000). + +.TP +.B bzip-small +Если для этого параметра установлено значение "true", алгоритм bzip попытается уменьшить использование системной памяти. Также для этого параметра можно установить значение "false" (по умолчанию установлено это значение). + +.TP +.B remove-hll +Если для этого параметра установлено значение "true", файлы HLL будут удалены после компиляции в CIL. Чтобы удалить уже cкомпилированные в CIL файлы HLL, необходимо перекомпилировать модули, установив для параметра +.BR ignore-module-cache +значение "true", или используя параметр +.BR ignore-module-cache +с semodule. Для параметра remove-hll можно установить либо значение "true", либо значение "false" (по умолчанию установлено "false"). + +Обратите внимание: так как этот параметр удаляет все файлы HLL, обновлённый компилятор HLL не сможет перекомпилировать исходный файл HLL в CIL. +Чтобы скомпилировать исходный файл HLL в CIL, необходимо переустановить этот файл HLL. + +.SH "СМОТРИТЕ ТАКЖЕ" +.TP +semanage(8) +.PP + +.SH АВТОРЫ +Эта страница руководства была написана Guido Trentalancia . +Библиотека управления SELinux была написана Tresys Technology LLC и Red Hat Inc. +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..dc87c59 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,4 @@ +semanageswig_wrap.c +semanageswig_python_exception.i +semanage.py +semanageswig_ruby_wrap.c diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..e029f09 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,166 @@ +# 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 ?= python3 +PYPREFIX ?= $(shell $(PYTHON) -c 'import sys;print("python-%d.%d" % sys.version_info[:2])') +RUBY ?= ruby +RUBYPREFIX ?= $(notdir $(RUBY)) +PKG_CONFIG ?= pkg-config + +# Installation directories. +PREFIX ?= /usr +LIBDIR ?= $(PREFIX)/lib +INCLUDEDIR ?= $(PREFIX)/include +PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX)) +PYLIBS ?= $(shell $(PKG_CONFIG) --libs $(PYPREFIX)) +PYTHONLIBDIR ?= $(shell $(PYTHON) -c "from distutils.sysconfig import *; print(get_python_lib(plat_specific=1, prefix='$(PREFIX)'))") +PYCEXT ?= $(shell $(PYTHON) -c 'import imp;print([s for s,m,t in imp.get_suffixes() if t == imp.C_EXTENSION][0])') +RUBYINC ?= $(shell $(RUBY) -e 'puts "-I" + RbConfig::CONFIG["rubyarchhdrdir"] + " -I" + RbConfig::CONFIG["rubyhdrdir"]') +RUBYLIBS ?= $(shell $(RUBY) -e 'puts "-L" + RbConfig::CONFIG["libdir"] + " -L" + RbConfig::CONFIG["archlibdir"] + " " + RbConfig::CONFIG["LIBRUBYARG_SHARED"]') +RUBYINSTALL ?= $(shell $(RUBY) -e 'puts RbConfig::CONFIG["vendorarchdir"]') + +DEFAULT_SEMANAGE_CONF_LOCATION=/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 $(sort $(wildcard conf-*.[ch])) +SRCS= $(filter-out $(GENERATED),$(sort $(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 -D_GNU_SOURCE +RANLIB ?= ranlib + +SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./ + +SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ + +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) -L. -shared -o $@ $< -lsemanage $(PYLIBS) + +$(SWIGRUBYSO): $(SWIGRUBYLOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -L. -shared -o $@ $^ -lsemanage $(RUBYLIBS) + +$(LIBA): $(OBJS) + $(AR) rcs $@ $^ + $(RANLIB) $@ + +$(LIBSO): $(LOBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -lsepol -laudit -lselinux -lbz2 -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@:$(LIBDIR):; s:@includedir@:$(INCLUDEDIR):' < $< > $@ + +semanageswig_python_exception.i: ../include/semanage/semanage.h + bash -e exception.sh > $@ || (rm -f $@ ; false) + +conf-scan.c: conf-scan.l conf-parse.h + $(LEX) $(LFLAGS) -o $@ $< + +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 $(DESTDIR)$(LIBDIR) || install -m 755 -d $(DESTDIR)$(LIBDIR) + install -m 644 $(LIBA) $(DESTDIR)$(LIBDIR) + install -m 755 $(LIBSO) $(DESTDIR)$(LIBDIR) + test -d $(DESTDIR)$(LIBDIR)/pkgconfig || install -m 755 -d $(DESTDIR)$(LIBDIR)/pkgconfig + install -m 644 $(LIBPC) $(DESTDIR)$(LIBDIR)/pkgconfig + test -f $(DESTDIR)$(DEFAULT_SEMANAGE_CONF_LOCATION) || install -m 644 -D semanage.conf $(DESTDIR)$(DEFAULT_SEMANAGE_CONF_LOCATION) + cd $(DESTDIR)$(LIBDIR) && ln -sf $(LIBSO) $(TARGET) + +install-pywrap: pywrap + test -d $(DESTDIR)$(PYTHONLIBDIR) || install -m 755 -d $(DESTDIR)$(PYTHONLIBDIR) + install -m 755 $(SWIGSO) $(DESTDIR)$(PYTHONLIBDIR)/_semanage$(PYCEXT) + install -m 644 semanage.py $(DESTDIR)$(PYTHONLIBDIR) + + +install-rubywrap: rubywrap + test -d $(DESTDIR)$(RUBYINSTALL) || install -m 755 -d $(DESTDIR)$(RUBYINSTALL) + install -m 755 $(SWIGRUBYSO) $(DESTDIR)$(RUBYINSTALL)/semanage.so + +relabel: + /sbin/restorecon $(DESTDIR)$(LIBDIR)/$(LIBSO) + +clean: + -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(SWIGLOBJ) $(SWIGSO) $(SWIGRUBYSO) $(TARGET) conf-parse.c conf-parse.h conf-scan.c *.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/src/boolean_internal.h b/src/boolean_internal.h new file mode 100644 index 0000000..ad12b82 --- /dev/null +++ b/src/boolean_internal.h @@ -0,0 +1,44 @@ +#ifndef _SEMANAGE_BOOLEAN_INTERNAL_H_ +#define _SEMANAGE_BOOLEAN_INTERNAL_H_ + +#include +#include +#include +#include +#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/src/boolean_record.c b/src/boolean_record.c new file mode 100644 index 0000000..c234094 --- /dev/null +++ b/src/boolean_record.c @@ -0,0 +1,201 @@ +/* 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 +#include +#include "handle_internal.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 +#include + +/* 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 = -1; + const char *prefix = semanage_root(); + const char *storename = handle->conf->store_path; + const char *selinux_root = selinux_policy_root(); + char *oldroot; + char *olddir; + char *subname = NULL; + char *newroot = NULL; + char *end; + + if (!selinux_root) + return -1; + + oldroot = strdup(selinux_root); + if (!oldroot) + return -1; + olddir = strdup(oldroot); + if (!olddir) + goto out; + end = strrchr(olddir, '/'); + if (!end) + goto out; + end++; + *end = '\0'; + rc = asprintf(&newroot, "%s%s%s", prefix, olddir, storename); + if (rc < 0) + goto out; + + if (strcmp(oldroot, newroot)) { + rc = selinux_set_policy_root(newroot); + if (rc) + goto out; + } + + subname = selinux_boolean_sub(name); + if (!subname) { + rc = -1; + goto out; + } + + if (strcmp(oldroot, newroot)) { + rc = selinux_set_policy_root(oldroot); + if (rc) + goto out; + } + + rc = sepol_bool_set_name(handle->sepolh, boolean, subname); +out: + free(subname); + free(oldroot); + free(olddir); + free(newroot); + 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/src/booleans_active.c b/src/booleans_active.c new file mode 100644 index 0000000..0725aec --- /dev/null +++ b/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/src/booleans_activedb.c b/src/booleans_activedb.c new file mode 100644 index 0000000..9bcc9d7 --- /dev/null +++ b/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 +#include +#include +#include +#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/src/booleans_file.c b/src/booleans_file.c new file mode 100644 index 0000000..f79d0b4 --- /dev/null +++ b/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 +#include +#include +#include +#include +#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/src/booleans_local.c b/src/booleans_local.c new file mode 100644 index 0000000..508ac10 --- /dev/null +++ b/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/src/booleans_policy.c b/src/booleans_policy.c new file mode 100644 index 0000000..5cccf3d --- /dev/null +++ b/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/src/booleans_policydb.c b/src/booleans_policydb.c new file mode 100644 index 0000000..6869d6c --- /dev/null +++ b/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 +#include +#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/src/conf-parse.y b/src/conf-parse.y new file mode 100644 index 0000000..b527e89 --- /dev/null +++ b/src/conf-parse.y @@ -0,0 +1,562 @@ +/* Authors: Jason Tang + * James Athey + * + * 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 +#include +#include + +#include +#include +#include +#include + +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 ARG +%type 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/src/conf-scan.l b/src/conf-scan.l new file mode 100644 index 0000000..607bbf0 --- /dev/null +++ b/src/conf-scan.l @@ -0,0 +1,98 @@ +/* Authors: Jason Tang + * James Athey + * + * 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 +#include + +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]; +\"\" BEGIN INITIAL; semanage_lval.s = NULL; return ARG; +\".+\" BEGIN INITIAL; semanage_lval.s = my_qstrdup(semanage_text); return ARG; +.*[^\"\n] BEGIN INITIAL; semanage_lval.s = my_strdup(semanage_text); return 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/src/context_internal.h b/src/context_internal.h new file mode 100644 index 0000000..729bfc8 --- /dev/null +++ b/src/context_internal.h @@ -0,0 +1,11 @@ +#ifndef _SEMANAGE_CONTEXT_INTERNAL_H_ +#define _SEMANAGE_CONTEXT_INTERNAL_H_ + +#include +#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/src/context_record.c b/src/context_record.c new file mode 100644 index 0000000..a228565 --- /dev/null +++ b/src/context_record.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include +#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/src/database.c b/src/database.c new file mode 100644 index 0000000..fc4f717 --- /dev/null +++ b/src/database.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include +#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/src/database.h b/src/database.h new file mode 100644 index 0000000..6a4a164 --- /dev/null +++ b/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/src/database_activedb.c b/src/database_activedb.c new file mode 100644 index 0000000..1cce0b8 --- /dev/null +++ b/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 +#include +#include +#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/src/database_activedb.h b/src/database_activedb.h new file mode 100644 index 0000000..37196c9 --- /dev/null +++ b/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/src/database_file.c b/src/database_file.c new file mode 100644 index 0000000..a51269e --- /dev/null +++ b/src/database_file.c @@ -0,0 +1,221 @@ +/* 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 +#include +#include +#include +#include +#include +#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; + mode_t mask; + + if (!dbase_llist_is_modified(&dbase->llist)) + return STATUS_SUCCESS; + + fname = dbase->path[handle->is_in_transaction]; + + mask = umask(0077); + str = fopen(fname, "w"); + umask(mask); + 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/src/database_file.h b/src/database_file.h new file mode 100644 index 0000000..dbd11bc --- /dev/null +++ b/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 +#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/src/database_join.c b/src/database_join.c new file mode 100644 index 0000000..b9b35a6 --- /dev/null +++ b/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 + +#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/src/database_join.h b/src/database_join.h new file mode 100644 index 0000000..d477fc4 --- /dev/null +++ b/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/src/database_llist.c b/src/database_llist.c new file mode 100644 index 0000000..c8f4ff0 --- /dev/null +++ b/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 +#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 > 0) + 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/src/database_llist.h b/src/database_llist.h new file mode 100644 index 0000000..84994ef --- /dev/null +++ b/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/src/database_policydb.c b/src/database_policydb.c new file mode 100644 index 0000000..748a6ed --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#include + +#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/src/database_policydb.h b/src/database_policydb.h new file mode 100644 index 0000000..f782e0d --- /dev/null +++ b/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 +#include +#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/src/debug.c b/src/debug.c new file mode 100644 index 0000000..08a9e02 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,130 @@ +/* Author: Joshua Brindle + * Ivan Gyurdiev + * + * 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 +#include +#include +#include +#include +#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/src/debug.h b/src/debug.h new file mode 100644 index 0000000..92bfcf5 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,79 @@ +/* Author: Joshua Brindle + * Jason Tang + * Ivan Gyurdiev + * + * 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 +#include +#include +#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/src/direct_api.c b/src/direct_api.c new file mode 100644 index 0000000..abc3a4c --- /dev/null +++ b/src/direct_api.c @@ -0,0 +1,3010 @@ +/* Author: Jason Tang + * Christopher Ashworth + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "user_internal.h" +#include "seuser_internal.h" +#include "port_internal.h" +#include "ibpkey_internal.h" +#include "ibendport_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 +#include + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +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; + struct stat sb; + + if (semanage_check_init(sh, sh->conf->store_root_path)) + goto err; + + if (sh->create_store) + if (semanage_create_store(sh, 1)) + 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 (fcontext_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_HOMEDIRS), + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS), + semanage_fcontext_dbase_homedirs(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; + + if (ibpkey_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_IBPKEYS_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_IBPKEYS_LOCAL), + semanage_ibpkey_dbase_local(sh)) < 0) + goto err; + + if (ibendport_file_dbase_init(sh, + semanage_path(SEMANAGE_ACTIVE, + SEMANAGE_IBENDPORTS_LOCAL), + semanage_path(SEMANAGE_TMP, + SEMANAGE_IBENDPORTS_LOCAL), + semanage_ibendport_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 (ibpkey_policydb_dbase_init(sh, semanage_ibpkey_dbase_policy(sh)) < 0) + goto err; + + if (ibendport_policydb_dbase_init(sh, semanage_ibendport_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 (stat(path, &sb) == 0) + sepol_set_disable_dontaudit(sh->sepolh, 1); + else if (errno == ENOENT) { + /* The file does not exist */ + sepol_set_disable_dontaudit(sh->sepolh, 0); + } else { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + goto err; + } + + 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_remove_tmps(semanage_handle_t *sh) +{ + if (sh->commit_err) + return 0; + + /* destroy sandbox if it exists */ + if (semanage_remove_directory + (semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)) < 0) { + if (errno != ENOENT) { + ERR(sh, "Could not cleanly remove sandbox %s.", + semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); + return -1; + } + } + + /* destroy tmp policy if it exists */ + if (semanage_remove_directory + (semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)) < 0) { + if (errno != ENOENT) { + ERR(sh, "Could not cleanly remove tmp %s.", + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FINAL_TOPLEVEL)); + return -1; + } + } + + return 0; +} + +static int semanage_direct_disconnect(semanage_handle_t *sh) +{ + int retval = 0; + + /* destroy transaction and remove tmp files if no commit error */ + if (sh->is_in_transaction) { + retval = semanage_remove_tmps(sh); + 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)); + ibpkey_file_dbase_release(semanage_ibpkey_dbase_local(sh)); + ibendport_file_dbase_release(semanage_ibendport_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)); + fcontext_file_dbase_release(semanage_fcontext_dbase_homedirs(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)); + ibpkey_policydb_dbase_release(semanage_ibpkey_dbase_policy(sh)); + ibendport_policydb_dbase_release(semanage_ibendport_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 retval; +} + +static int semanage_direct_begintrans(semanage_handle_t * sh) +{ + 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 *********************/ + +/* 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. + */ +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; + *module_name = *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); + sepol_policy_file_free(pf); + + return 0; +} + +#include +#include +#include +#include + +/* 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) { + /* + * Write the users_extra entries from CIL modules. + * This file is used as our baseline when we do not require + * re-linking. + */ + ofilename = semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_EXTRA_LINKED); + if (ofilename == NULL) { + retval = -1; + goto cleanup; + } + retval = write_file(sh, ofilename, data, size); + if (retval < 0) + goto cleanup; + + /* + * Write the users_extra file; users_extra.local + * will be merged into this file. + */ + ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA); + if (ofilename == NULL) { + retval = -1; + goto cleanup; + } + retval = write_file(sh, ofilename, data, size); + if (retval < 0) + goto cleanup; + + 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) { + /* + * Write the seusers entries from CIL modules. + * This file is used as our baseline when we do not require + * re-linking. + */ + ofilename = semanage_path(SEMANAGE_TMP, + SEMANAGE_SEUSERS_LINKED); + if (ofilename == NULL) { + retval = -1; + goto cleanup; + } + retval = write_file(sh, ofilename, data, size); + if (retval < 0) + goto cleanup; + + /* + * Write the seusers file; seusers.local will be merged into + * this file. + */ + ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); + if (ofilename == NULL) { + retval = -1; + goto cleanup; + } + retval = write_file(sh, ofilename, data, size); + if (retval < 0) + goto cleanup; + + 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] = {-1, -1}; + int output_fd[2] = {-1, -1}; + int err_fd[2] = {-1, -1}; + 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, + const 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; + + return 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 = 0; + size_t err_data_len = 0; + + 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]; + struct stat sb; + + 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 && + (status = stat(cil_path, &sb)) == 0) { + continue; + } + if (status != 0 && errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", cil_path, strerror(errno)); + goto cleanup; //an error in the "stat" call + } + + status = semanage_compile_module(sh, &modinfos[i]); + if (status < 0) { + goto cleanup; + } + } + + status = 0; + +cleanup: + return status; +} + +/* Copies a file from src to dst. If dst already exists then + * overwrite it. If source doesn't exist then return success. + * Returns 0 on success, -1 on error. */ +static int copy_file_if_exists(const char *src, const char *dst, mode_t mode){ + int rc = semanage_copy_file(src, dst, mode, false); + return (rc < 0 && errno != ENOENT) ? rc : 0; +} + +/********************* 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; + sepol_policydb_t *out = NULL; + struct cil_db *cildb = NULL; + semanage_module_info_t *modinfos = NULL; + mode_t mask = umask(0077); + struct stat sb; + + int do_rebuild, do_write_kernel, do_install; + int fcontexts_modified, ports_modified, seusers_modified, + disable_dontaudit, preserve_tunables, ibpkeys_modified, + ibendports_modified; + 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 *pusers_extra = semanage_user_extra_dbase_policy(sh); + dbase_config_t *ports = semanage_port_dbase_local(sh); + dbase_config_t *pports = semanage_port_dbase_policy(sh); + dbase_config_t *ibpkeys = semanage_ibpkey_dbase_local(sh); + dbase_config_t *pibpkeys = semanage_ibpkey_dbase_policy(sh); + dbase_config_t *ibendports = semanage_ibendport_dbase_local(sh); + dbase_config_t *pibendports = semanage_ibendport_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); + dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh); + + /* Modified flags that we need to use more than once. */ + ports_modified = ports->dtable->is_modified(ports->dbase); + ibpkeys_modified = ibpkeys->dtable->is_modified(ibpkeys->dbase); + ibendports_modified = ibendports->dtable->is_modified(ibendports->dbase); + seusers_modified = seusers->dtable->is_modified(seusers->dbase); + fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase); + + /* Rebuild if explicitly requested or any module changes occurred. */ + do_rebuild = sh->do_rebuild | sh->modules_modified; + + /* Create or remove the disable_dontaudit flag file. */ + path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT); + if (stat(path, &sb) == 0) + do_rebuild |= !(sepol_get_disable_dontaudit(sh->sepolh) == 1); + else if (errno == ENOENT) { + /* The file does not exist */ + do_rebuild |= (sepol_get_disable_dontaudit(sh->sepolh) == 1); + } else { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + retval = -1; + goto cleanup; + } + 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 (stat(path, &sb) == 0) + do_rebuild |= !(sepol_get_preserve_tunables(sh->sepolh) == 1); + else if (errno == ENOENT) { + /* The file does not exist */ + do_rebuild |= (sepol_get_preserve_tunables(sh->sepolh) == 1); + } else { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + retval = -1; + goto cleanup; + } + + 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; + } + + /* + * 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. + * This also ensures that any linked files that are required + * in order to skip re-linking are present; otherwise, we force + * a rebuild. + */ + if (!do_rebuild) { + int files[] = {SEMANAGE_STORE_KERNEL, + SEMANAGE_STORE_FC, + SEMANAGE_STORE_SEUSERS, + SEMANAGE_LINKED, + SEMANAGE_SEUSERS_LINKED, + SEMANAGE_USERS_EXTRA_LINKED}; + + for (i = 0; i < (int) ARRAY_SIZE(files); i++) { + path = semanage_path(SEMANAGE_TMP, files[i]); + if (stat(path, &sb) != 0) { + if (errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + retval = -1; + goto cleanup; + } + + do_rebuild = 1; + goto rebuild; + } + } + } + +rebuild: + /* + * Now that we know whether or not a rebuild is required, + * we can determine what else needs to be done. + * We need to write the kernel policy if we are rebuilding + * or if any other policy component that lives in the kernel + * policy has been modified. + * We need to install the policy files if any of the managed files + * that live under /etc/selinux (kernel policy, seusers, file contexts) + * will be modified. + */ + do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified | + ibendports_modified | + bools->dtable->is_modified(bools->dbase) | + ifaces->dtable->is_modified(ifaces->dbase) | + nodes->dtable->is_modified(nodes->dbase) | + users->dtable->is_modified(users_base->dbase); + do_install = do_write_kernel | seusers_modified | fcontexts_modified; + + /* + * If there were policy changes, or explicitly requested, or + * any required files are missing, rebuild the policy. + */ + if (do_rebuild) { + /* =================== 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); + + /* Write the linked policy before merging local changes. */ + retval = semanage_write_policydb(sh, out, + SEMANAGE_LINKED); + if (retval < 0) + goto cleanup; + } else { + /* Load the existing linked policy, w/o local changes */ + retval = sepol_policydb_create(&out); + if (retval < 0) + goto cleanup; + + retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED); + if (retval < 0) + goto cleanup; + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED); + if (stat(path, &sb) == 0) { + retval = semanage_copy_file(path, + semanage_path(SEMANAGE_TMP, + SEMANAGE_STORE_SEUSERS), + 0, false); + if (retval < 0) + goto cleanup; + pseusers->dtable->drop_cache(pseusers->dbase); + } else if (errno == ENOENT) { + /* The file does not exist */ + pseusers->dtable->clear(sh, pseusers->dbase); + } else { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + retval = -1; + goto cleanup; + } + + path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED); + if (stat(path, &sb) == 0) { + retval = semanage_copy_file(path, + semanage_path(SEMANAGE_TMP, + SEMANAGE_USERS_EXTRA), + 0, false); + if (retval < 0) + goto cleanup; + pusers_extra->dtable->drop_cache(pusers_extra->dbase); + } else if (errno == ENOENT) { + /* The file does not exist */ + pusers_extra->dtable->clear(sh, pusers_extra->dbase); + } else { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + retval = -1; + goto cleanup; + } + } + + /* Attach our databases to the policydb we just created or loaded. */ + 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 *) pibpkeys->dbase, out); + dbase_policydb_attach((dbase_policydb_t *) pibendports->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); + + /* Merge local changes */ + retval = semanage_base_merge_components(sh); + if (retval < 0) + goto cleanup; + + if (do_write_kernel) { + /* Write new kernel policy. */ + retval = semanage_write_policydb(sh, out, + SEMANAGE_STORE_KERNEL); + if (retval < 0) + goto cleanup; + + /* Run the kernel policy verifier, if any. */ + retval = semanage_verify_kernel(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 (do_rebuild || fcontexts_modified) { + retval = semanage_fcontext_validate_local(sh, out); + if (retval < 0) + goto cleanup; + } + + /* Validate local seusers against policy */ + if (do_rebuild || seusers_modified) { + retval = semanage_seuser_validate_local(sh, out); + if (retval < 0) + goto cleanup; + } + + /* Validate local ports for overlap */ + if (do_rebuild || ports_modified) { + retval = semanage_port_validate_local(sh); + if (retval < 0) + goto cleanup; + } + + /* Validate local ibpkeys for overlap */ + if (do_rebuild || ibpkeys_modified) { + retval = semanage_ibpkey_validate_local(sh); + if (retval < 0) + goto cleanup; + } + + /* Validate local ibendports */ + if (do_rebuild || ibendports_modified) { + retval = semanage_ibendport_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, false); + if (retval < 0) { + goto cleanup; + } + + retval = copy_file_if_exists(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; + } + + retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC), + sh->conf->file_mode); + if (retval < 0) { + goto cleanup; + } + + retval = copy_file_if_exists(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){ + if ((retval = semanage_genhomedircon(sh, out, sh->conf->usepasswd, + sh->conf->ignoredirs)) != 0) { + ERR(sh, "semanage_genhomedircon returned error code %d.", retval); + goto cleanup; + } + /* file_contexts.homedirs was created in SEMANAGE_TMP store */ + retval = semanage_copy_file( + semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS), + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS), + sh->conf->file_mode, false); + if (retval < 0) { + 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 (do_install) + 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]); + } + + /* 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 *) pibpkeys->dbase); + dbase_policydb_detach((dbase_policydb_t *) pibendports->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); + + free(fc_buffer); + + /* Set commit_err so other functions can detect any errors. Note that + * retval > 0 will be the commit number. + */ + if (retval < 0) + sh->commit_err = retval; + + if (semanage_remove_tmps(sh) != 0) + retval = -1; + + semanage_release_trans_lock(sh); + umask(mask); + + 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 *module_name = NULL; + char *separator; + char *version = NULL; + + 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; + } + + if (strcmp(lang_ext, "pp") == 0) { + retval = parse_module_headers(sh, data, data_len, &module_name, &version); + free(version); + if (retval != 0) + goto cleanup; + } + + if (module_name == NULL) { + module_name = strdup(filename); + if (module_name == NULL) { + ERR(sh, "No memory available for module_name.\n"); + retval = -1; + goto cleanup; + } + } else if (strcmp(module_name, filename) != 0) { + fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename); + } + + retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext); + +cleanup: + if (data_len > 0) munmap(data, data_len); + free(module_name); + 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; + struct stat sb; + + /* 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 (stat(module_path, &sb) != 0) { + ERR(sh, "Unable to access %s: %s\n", module_path, strerror(errno)); + 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") && stat(input_file, &sb) != 0) { + if (errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", input_file, strerror(errno)); + rc = -1; + goto cleanup; + } + + 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) { + if (errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + status = -1; + goto cleanup; + } + + *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; + mode_t mask; + + /* 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 */ + mask = umask(0077); + fp = fopen(fn, "w"); + umask(mask); + + 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); + + 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, SEMANAGE_STORE_KERNEL); + 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; + + /* 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) { + if (errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", fn, strerror(errno)); + status = -1; + goto cleanup; + } + + 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) != 0) { + ERR(sh, + "Unable to close %s module lang ext file.", + (*modinfo)->name); + status = -1; + } + + 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; + } + + semanage_module_info_destroy(sh, modinfo_tmp); + 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); + } + + semanage_module_info_destroy(sh, modinfo_tmp); + 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; + struct stat sb; + + char path[PATH_MAX]; + mode_t mask = umask(0077); + + 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 as there is a disabled instance of this module present in the system.", + 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 (stat(path, &sb) == 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); + umask(mask); + + 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/src/direct_api.h b/src/direct_api.h new file mode 100644 index 0000000..e56107b --- /dev/null +++ b/src/direct_api.h @@ -0,0 +1,46 @@ +/* Authors: Jason Tang + * + * 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 +#include +ssize_t bunzip(struct semanage_handle *sh, FILE *f, char **data); + +#endif diff --git a/src/dso.h b/src/dso.h new file mode 100644 index 0000000..8c9a014 --- /dev/null +++ b/src/dso.h @@ -0,0 +1,23 @@ +#ifndef _SEMANAGE_DSO_H +#define _SEMANAGE_DSO_H 1 + +#ifdef SHARED +# define hidden __attribute__ ((visibility ("hidden"))) +# define hidden_proto(fct) __hidden_proto (fct, fct##_internal) +# define __hidden_proto(fct, internal) \ + extern __typeof (fct) internal; \ + extern __typeof (fct) fct __asm (#internal) hidden; +# if defined(__alpha__) || defined(__mips__) +# define hidden_def(fct) \ + asm (".globl " #fct "\n" #fct " = " #fct "_internal"); +# else +# define hidden_def(fct) \ + asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); +#endif +#else +# define hidden +# define hidden_proto(fct) +# define hidden_def(fct) +#endif + +#endif diff --git a/src/exception.sh b/src/exception.sh new file mode 100644 index 0000000..97bc2ae --- /dev/null +++ b/src/exception.sh @@ -0,0 +1,18 @@ +function except() { +echo " +%exception $1 { + \$action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + SWIG_fail; + } +} +" +} +if ! ${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h +then + # clang does not support -aux-info so fall back to gcc + gcc -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h +fi +for i in `awk '/extern int/ { print $6 }' temp.aux`; do except $i ; done +rm -f -- temp.aux -.o diff --git a/src/fcontext_internal.h b/src/fcontext_internal.h new file mode 100644 index 0000000..a6008ea --- /dev/null +++ b/src/fcontext_internal.h @@ -0,0 +1,43 @@ +#ifndef _SEMANAGE_FCONTEXT_INTERNAL_H_ +#define _SEMANAGE_FCONTEXT_INTERNAL_H_ + +#include +#include +#include +#include +#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/src/fcontext_record.c b/src/fcontext_record.c new file mode 100644 index 0000000..f39efa1 --- /dev/null +++ b/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 +#include +#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/src/fcontexts_file.c b/src/fcontexts_file.c new file mode 100644 index 0000000..1e59651 --- /dev/null +++ b/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 +#include +#include +#include +#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, "<>\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/src/fcontexts_local.c b/src/fcontexts_local.c new file mode 100644 index 0000000..b0da236 --- /dev/null +++ b/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 +#include +#include +#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/src/fcontexts_policy.c b/src/fcontexts_policy.c new file mode 100644 index 0000000..98490ab --- /dev/null +++ b/src/fcontexts_policy.c @@ -0,0 +1,61 @@ +/* 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); +} + +int semanage_fcontext_list_homedirs(semanage_handle_t * handle, + semanage_fcontext_t *** records, unsigned int *count) +{ + + dbase_config_t *dconfig = semanage_fcontext_dbase_homedirs(handle); + return dbase_list(handle, dconfig, records, count); +} diff --git a/src/genhomedircon.c b/src/genhomedircon.c new file mode 100644 index 0000000..e5f8d37 --- /dev/null +++ b/src/genhomedircon.c @@ -0,0 +1,1423 @@ +/* Author: Mark Goldman + * Paul Rosenfeld + * Todd C. Miller + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "semanage_store.h" +#include "seuser_internal.h" +#include "debug.h" + +#include "utilities.h" +#include "genhomedircon.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 FALLBACK_SENAME "user_u" +#define FALLBACK_PREFIX "user" +#define FALLBACK_LEVEL "s0" +#define FALLBACK_NAME "[^/]+" +#define FALLBACK_UIDGID "[0-9]+" +#define DEFAULT_LOGIN "__default__" + +#define CONTEXT_NONE "<>" + +typedef struct user_entry { + char *name; + char *uid; + char *gid; + char *sename; + char *prefix; + char *home; + char *level; + char *login; + char *homedir_role; + 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 int prefix_is_homedir_role(const semanage_user_t *user, + const char *prefix) +{ + return strcmp(OBJECT_R, prefix) == 0 || + semanage_user_has_role(user, prefix); +} + +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; + char *expr = NULL; + regex_t re; + int type, retval = -1; + size_t len; + + /* Only match ALL or DIR */ + type = semanage_fcontext_get_type(fcontext); + if (type != SEMANAGE_FCONTEXT_ALL && type != SEMANAGE_FCONTEXT_DIR) + return 0; + + len = strlen(oexpr); + /* Define a macro to strip a literal string from the end of oexpr */ +#define rstrip_oexpr_len(cstr, cstrlen) \ + do { \ + if (len >= (cstrlen) && !strncmp(oexpr + len - (cstrlen), (cstr), (cstrlen))) \ + len -= (cstrlen); \ + } while (0) +#define rstrip_oexpr(cstr) rstrip_oexpr_len(cstr, sizeof(cstr) - 1) + + rstrip_oexpr(".+"); + rstrip_oexpr(".*"); + rstrip_oexpr("(/.*)?"); + rstrip_oexpr("/"); + +#undef rstrip_oexpr_len +#undef rstrip_oexpr + + /* Anchor oexpr at the beginning and append pattern to eat up trailing slashes */ + if (asprintf(&expr, "^%.*s/*$", (int)len, oexpr) < 0) + return -1; + + /* Check dir against expr */ + if (regcomp(&re, expr, REG_EXTENDED) != 0) + goto done; + if (regexec(&re, handp->dir, 0, NULL, 0) == 0) + handp->matched = 1; + regfree(&re); + + retval = 0; + +done: + 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 *path = NULL; + uid_t temp, minuid = 500, maxuid = 60000; + int minuid_set = 0; + struct passwd *pwbuf; + struct stat buf; + + 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; + + errno = 0; + setpwent(); + while (1) { + errno = 0; + pwbuf = getpwent(); + if (pwbuf == NULL) + break; + 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 (errno) { + WARN(s->h_semanage, "Error while fetching users. " + "Returning list so far."); + } + + if (semanage_list_sort(&homedir_list)) + goto fail; + + endpwent(); + semanage_list_destroy(&shells); + + return homedir_list; + + fail: + endpwent(); + 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); +} + +static int STR_COMPARATOR(const void *a, const void *b) +{ + return strcmp((const char *) a, (const char *) b); +} + +/* 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 char *replace_all(const char *str, const replacement_pair_t * repl) +{ + char *retval, *retval2; + int i; + + if (!str || !repl) + return NULL; + + retval = strdup(str); + for (i = 0; retval != NULL && repl[i].search_for; i++) { + retval2 = semanage_str_replace(repl[i].search_for, + repl[i].replace_with, retval, 0); + free(retval); + retval = retval2; + } + return retval; +} + +static const char *extract_context(const char *line) +{ + const char *p = line; + size_t off; + + off = strlen(p); + p += off; + /* consider trailing whitespaces */ + while (off > 0) { + p--; + off--; + if (!isspace(*p)) + break; + } + if (off == 0) + return NULL; + + /* find the last field in line */ + while (off > 0 && !isspace(*(p - 1))) { + p--; + off--; + } + return p; +} + +static int check_line(genhomedircon_settings_t * s, const char *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) { + result = sepol_context_check(s->h_semanage->sepolh, + s->policydb, ctx_record); + 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) +{ + char *line; + + for (; tpl; tpl = tpl->next) { + line = replace_all(tpl->data, repl); + if (!line) + goto fail; + if (check_line(s, line) == STATUS_SUCCESS) { + if (fprintf(out, "%s\n", line) < 0) + goto fail; + } + free(line); + } + return STATUS_SUCCESS; + + fail: + free(line); + return STATUS_ERR; +} + +static int write_contexts(genhomedircon_settings_t *s, FILE *out, + semanage_list_t *tpl, const replacement_pair_t *repl, + const genhomedircon_user_entry_t *user) +{ + char *line, *temp; + sepol_context_t *context; + char *new_context_str; + + for (; tpl; tpl = tpl->next) { + context = NULL; + new_context_str = NULL; + line = replace_all(tpl->data, repl); + if (!line) { + goto fail; + } + + const char *old_context_str = extract_context(line); + if (!old_context_str) { + goto fail; + } + + if (strcmp(old_context_str, CONTEXT_NONE) == 0) { + if (check_line(s, line) == STATUS_SUCCESS && + fprintf(out, "%s\n", line) < 0) { + goto fail; + } + free(line); + continue; + } + + sepol_handle_t *sepolh = s->h_semanage->sepolh; + + if (sepol_context_from_string(sepolh, old_context_str, + &context) < 0) { + goto fail; + } + + if (sepol_context_set_user(sepolh, context, user->sename) < 0) { + goto fail; + } + + if (sepol_policydb_mls_enabled(s->policydb) && + sepol_context_set_mls(sepolh, context, user->level) < 0) { + goto fail; + } + + if (user->homedir_role && + sepol_context_set_role(sepolh, context, user->homedir_role) < 0) { + goto fail; + } + + if (sepol_context_to_string(sepolh, context, + &new_context_str) < 0) { + goto fail; + } + + temp = semanage_str_replace(old_context_str, new_context_str, + line, 1); + if (!temp) { + goto fail; + } + free(line); + line = temp; + + if (check_line(s, line) == STATUS_SUCCESS) { + if (fprintf(out, "%s\n", line) < 0) + goto fail; + } + + free(line); + sepol_context_free(context); + free(new_context_str); + } + + return STATUS_SUCCESS; +fail: + free(line); + sepol_context_free(context); + free(new_context_str); + 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_HOME_DIR,.replace_with = user->home}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {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_contexts(s, out, tpl, repl, user); +} + +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}, + {NULL, NULL} + }; + + return write_contexts(s, out, tpl, repl, user); +} + +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}, + {NULL, NULL} + }; + + return write_contexts(s, out, tpl, repl, user); +} + +static int seuser_sort_func(const void *arg1, const void *arg2) +{ + const semanage_seuser_t **u1 = (const semanage_seuser_t **) arg1; + const semanage_seuser_t **u2 = (const semanage_seuser_t **) arg2;; + const char *name1 = semanage_seuser_get_name(*u1); + const char *name2 = semanage_seuser_get_name(*u2); + + if (name1[0] == '%' && name2[0] == '%') { + return 0; + } else if (name1[0] == '%') { + return 1; + } else if (name2[0] == '%') { + return -1; + } + + return strcmp(name1, name2); +} + +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, + const char *ln, const char *hd_role) +{ + 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; + char *lname = NULL; + char *homedir_role = 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; + lname = strdup(ln); + if (!lname) + goto cleanup; + if (hd_role) { + homedir_role = strdup(hd_role); + if (!homedir_role) + goto cleanup; + } + + temp->name = name; + temp->uid = uid; + temp->gid = gid; + temp->sename = sename; + temp->prefix = prefix; + temp->home = home; + temp->level = level; + temp->login = lname; + temp->homedir_role = homedir_role; + temp->next = (*list); + (*list) = temp; + + return STATUS_SUCCESS; + + cleanup: + free(name); + free(uid); + free(gid); + free(sename); + free(prefix); + free(home); + free(level); + free(lname); + free(homedir_role); + 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->login); + free(temp->homedir_role); + 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; + const char *homedir_role = 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 (prefix_is_homedir_role(u, prefix)) { + homedir_role = prefix; + } + + if (push_user_entry(&(s->fallback), FALLBACK_NAME, + FALLBACK_UIDGID, FALLBACK_UIDGID, + seuname, prefix, "", level, + FALLBACK_NAME, homedir_role) != 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 *find_user(genhomedircon_user_entry_t *head, + const char *name) +{ + for(; head; head = head->next) { + if (strcmp(head->name, name) == 0) { + return head; + } + } + + return NULL; +} + +static int add_user(genhomedircon_settings_t * s, + genhomedircon_user_entry_t **head, + semanage_user_t *user, + const char *name, + const char *sename, + const char *selogin) +{ + if (selogin[0] == '%') { + genhomedircon_user_entry_t *orig = find_user(*head, name); + if (orig != NULL && orig->login[0] == '%') { + ERR(s->h_semanage, "User %s is already mapped to" + " group %s, but also belongs to group %s. Add an" + " explicit mapping for this user to" + " override group mappings.", + name, orig->login + 1, selogin + 1); + return STATUS_ERR; + } else if (orig != NULL) { + // user mappings take precedence + return STATUS_SUCCESS; + } + } + + int retval = STATUS_ERR; + + char *rbuf = NULL; + long rbuflen; + struct passwd pwstorage, *pwent = NULL; + const char *prefix = NULL; + const char *level = NULL; + const char *homedir_role = NULL; + char uid[11]; + char gid[11]; + + errno = 0; + /* Allocate space for the getpwnam_r buffer */ + rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen == -1 && errno == 0) + /* sysconf returning -1 with no errno means indeterminate size */ + rbuflen = 1024; + else if (rbuflen <= 0) + goto cleanup; + rbuf = malloc(rbuflen); + if (rbuf == NULL) + goto cleanup; + + if (user) { + prefix = semanage_user_get_prefix(user); + level = semanage_user_get_mlslevel(user); + + if (!level) { + level = FALLBACK_LEVEL; + } + } else { + prefix = name; + level = FALLBACK_LEVEL; + } + + if (prefix_is_homedir_role(user, prefix)) { + homedir_role = prefix; + } + + retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (retval != 0 || pwent == NULL) { + if (retval != 0 && retval != ENOENT) { + goto cleanup; + } + + WARN(s->h_semanage, + "user %s not in password file", name); + retval = STATUS_SUCCESS; + goto cleanup; + } + + 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 */ + retval = STATUS_SUCCESS; + goto cleanup; + } + + if (ignore(pwent->pw_dir)) { + retval = STATUS_SUCCESS; + goto cleanup; + } + + len = snprintf(uid, sizeof(uid), "%u", pwent->pw_uid); + if (len < 0 || len >= (int)sizeof(uid)) { + goto cleanup; + } + + len = snprintf(gid, sizeof(gid), "%u", pwent->pw_gid); + if (len < 0 || len >= (int)sizeof(gid)) { + goto cleanup; + } + + retval = push_user_entry(head, name, uid, gid, sename, prefix, + pwent->pw_dir, level, selogin, homedir_role); +cleanup: + free(rbuf); + return retval; +} + +static int get_group_users(genhomedircon_settings_t * s, + genhomedircon_user_entry_t **head, + semanage_user_t *user, + const char *sename, + const char *selogin) +{ + int retval = STATUS_ERR; + unsigned int i; + + long grbuflen; + char *grbuf = NULL; + struct group grstorage, *group = NULL; + struct passwd *pw = NULL; + + errno = 0; + grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuflen == -1 && errno == 0) + /* sysconf returning -1 with no errno means indeterminate size */ + grbuflen = 1024; + else if (grbuflen <= 0) + goto cleanup; + grbuf = malloc(grbuflen); + if (grbuf == NULL) + goto cleanup; + + const char *grname = selogin + 1; + + errno = 0; + while ( + (retval = getgrnam_r(grname, &grstorage, grbuf, (size_t) grbuflen, &group)) != 0 && + errno == ERANGE + ) { + char *new_grbuf; + grbuflen *= 2; + if (grbuflen < 0) + /* the member list could exceed 2Gb on a system with a 32-bit CPU (where + * sizeof(long) = 4) - if this ever happened, the loop would become infinite. */ + goto cleanup; + new_grbuf = realloc(grbuf, grbuflen); + if (new_grbuf == NULL) + goto cleanup; + grbuf = new_grbuf; + } + if (retval != 0) + goto cleanup; + + if (group == NULL) { + ERR(s->h_semanage, "Can't find group named %s\n", grname); + goto cleanup; + } + + size_t nmembers = 0; + char **members = group->gr_mem; + + while (*members != NULL) { + nmembers++; + members++; + } + + for (i = 0; i < nmembers; i++) { + const char *uname = group->gr_mem[i]; + + if (add_user(s, head, user, uname, sename, selogin) < 0) { + goto cleanup; + } + } + + setpwent(); + while (1) { + errno = 0; + pw = getpwent(); + if (pw == NULL) + break; + // skip users who also have this group as their + // primary group + if (lfind(pw->pw_name, group->gr_mem, &nmembers, + sizeof(char *), &STR_COMPARATOR)) { + continue; + } + + if (group->gr_gid == pw->pw_gid) { + if (add_user(s, head, user, pw->pw_name, + sename, selogin) < 0) { + goto cleanup; + } + } + } + + retval = STATUS_SUCCESS; +cleanup: + endpwent(); + free(grbuf); + + return retval; +} + +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; + unsigned int i; + 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(seuser_list, nseusers, sizeof(semanage_seuser_t *), + &seuser_sort_func); + qsort(user_list, nusers, sizeof(semanage_user_t *), + (int (*)(const void *, const void *))&user_sort_func); + + 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, DEFAULT_LOGIN) == 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); + + /* %groupname syntax */ + if (name[0] == '%') { + retval = get_group_users(s, &head, *u, seuname, + name); + } else { + retval = add_user(s, &head, *u, name, + seuname, name); + } + + if (retval != 0) { + *errors = STATUS_ERR; + goto cleanup; + } + } + + cleanup: + 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) { + char *temp = NULL; + + if (asprintf(&temp, "%s/%s", h->data, FALLBACK_NAME) < 0) { + retval = STATUS_ERR; + goto done; + } + + free(s->fallback->home); + s->fallback->home = temp; + + if (write_home_dir_context(s, out, homedir_context_tpl, + s->fallback) != STATUS_SUCCESS) { + 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) { + free(temp); + s->fallback->home = NULL; + retval = STATUS_ERR; + goto done; + } + + 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_path(SEMANAGE_TMP, SEMANAGE_STORE_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); + + while (s.fallback) + pop_user_entry(&(s.fallback)); + + ignore_free(); + + return retval; +} diff --git a/src/genhomedircon.h b/src/genhomedircon.h new file mode 100644 index 0000000..3f9ef8f --- /dev/null +++ b/src/genhomedircon.h @@ -0,0 +1,29 @@ +/* Author: Mark Goldman + * + * 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/src/handle.c b/src/handle.c new file mode 100644 index 0000000..e5109ae --- /dev/null +++ b/src/handle.c @@ -0,0 +1,434 @@ +/* Author: Joshua Brindle + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#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; +} + +hidden_def(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; + + sh->commit_err = 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/src/handle.h b/src/handle.h new file mode 100644 index 0000000..a91907b --- /dev/null +++ b/src/handle.h @@ -0,0 +1,268 @@ +/* Author: Joshua Brindle + * Jason Tang + * Ivan Gyurdiev + * + * 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 +#include +#include "handle_internal.h" +#include +#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 commit_err; /* set by semanage_direct_commit() if there are + * any errors when building or committing the + * sandbox to kernel policy at /etc/selinux + */ + 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 24 + +/* 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 +#define DBASE_LOCAL_IBPKEYS 9 +#define DBASE_LOCAL_IBENDPORTS 10 + +/* Policy + Local modifications */ +#define DBASE_POLICY_USERS_BASE 11 +#define DBASE_POLICY_USERS_EXTRA 12 +#define DBASE_POLICY_USERS 13 +#define DBASE_POLICY_PORTS 14 +#define DBASE_POLICY_INTERFACES 15 +#define DBASE_POLICY_BOOLEANS 16 +#define DBASE_POLICY_FCONTEXTS 17 +#define DBASE_POLICY_FCONTEXTS_H 18 +#define DBASE_POLICY_SEUSERS 19 +#define DBASE_POLICY_NODES 20 +#define DBASE_POLICY_IBPKEYS 21 +#define DBASE_POLICY_IBENDPORTS 22 + +/* Active kernel policy */ +#define DBASE_ACTIVE_BOOLEANS 23 + 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_ibpkey_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_IBPKEYS]; +} + +static inline + dbase_config_t * semanage_ibendport_dbase_local(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_LOCAL_IBENDPORTS]; +} + +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_ibpkey_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_IBPKEYS]; +} + +static inline + dbase_config_t * semanage_ibendport_dbase_policy(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_IBENDPORTS]; +} + +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_fcontext_dbase_homedirs(semanage_handle_t * handle) +{ + return &handle->dbase[DBASE_POLICY_FCONTEXTS_H]; +} + +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/src/handle_internal.h b/src/handle_internal.h new file mode 100644 index 0000000..d4b4d9c --- /dev/null +++ b/src/handle_internal.h @@ -0,0 +1,13 @@ +#ifndef _SEMANAGE_HANDLE_INTERNAL_H_ +#define _SEMANAGE_HANDLE_INTERNAL_H_ + +#include +#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) +hidden_proto(semanage_root) +#endif diff --git a/src/ibendport_internal.h b/src/ibendport_internal.h new file mode 100644 index 0000000..970fbdb --- /dev/null +++ b/src/ibendport_internal.h @@ -0,0 +1,48 @@ +#ifndef _SEMANAGE_IBENDPORT_INTERNAL_H_ +#define _SEMANAGE_IBENDPORT_INTERNAL_H_ + +#include +#include +#include +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_ibendport_create) +hidden_proto(semanage_ibendport_compare) +hidden_proto(semanage_ibendport_compare2) +hidden_proto(semanage_ibendport_clone) +hidden_proto(semanage_ibendport_free) +hidden_proto(semanage_ibendport_key_extract) +hidden_proto(semanage_ibendport_key_free) +hidden_proto(semanage_ibendport_get_port) +hidden_proto(semanage_ibendport_set_port) +hidden_proto(semanage_ibendport_get_con) +hidden_proto(semanage_ibendport_set_con) +hidden_proto(semanage_ibendport_list_local) +hidden_proto(semanage_ibendport_get_ibdev_name) +hidden_proto(semanage_ibendport_set_ibdev_name) + +/* IBENDPORT RECORD: method table */ +extern record_table_t SEMANAGE_IBENDPORT_RTABLE; + +extern int ibendport_file_dbase_init(semanage_handle_t *handle, + const char *path_ro, + const char *path_rw, + dbase_config_t *dconfig); + +extern void ibendport_file_dbase_release(dbase_config_t *dconfig); + +extern int ibendport_policydb_dbase_init(semanage_handle_t *handle, + dbase_config_t *dconfig); + +extern void ibendport_policydb_dbase_release(dbase_config_t *dconfig); + +extern int hidden semanage_ibendport_validate_local(semanage_handle_t *handle); + +/* ==== Internal (to ibendports) API === */ + +hidden int semanage_ibendport_compare2_qsort(const semanage_ibendport_t **ibendport, + const semanage_ibendport_t **ibendport2); + +#endif diff --git a/src/ibendport_record.c b/src/ibendport_record.c new file mode 100644 index 0000000..955067e --- /dev/null +++ b/src/ibendport_record.c @@ -0,0 +1,154 @@ +/*Copyright (C) 2005 Red Hat, Inc. */ + +/*Object: semanage_ibendport_t (Infiniband Pkey) + *Object: semanage_ibendport_key_t (Infiniband Pkey Key) + *Implements: record_t (Database Record) + *Implements: record_key_t (Database Record Key) + */ + +#include +#include + +typedef sepol_context_t semanage_context_t; +typedef sepol_ibendport_t semanage_ibendport_t; +typedef sepol_ibendport_key_t semanage_ibendport_key_t; +#define _SEMANAGE_IBENDPORT_DEFINED_ +#define _SEMANAGE_CONTEXT_DEFINED_ + +typedef semanage_ibendport_t record_t; +typedef semanage_ibendport_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "ibendport_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_ibendport_compare(const semanage_ibendport_t *ibendport, + const semanage_ibendport_key_t *key) +{ + return sepol_ibendport_compare(ibendport, key); +} + +hidden_def(semanage_ibendport_compare) + +int semanage_ibendport_compare2(const semanage_ibendport_t *ibendport, + const semanage_ibendport_t *ibendport2) +{ + return sepol_ibendport_compare2(ibendport, ibendport2); +} + +hidden_def(semanage_ibendport_compare2) + +hidden int semanage_ibendport_compare2_qsort(const semanage_ibendport_t **ibendport, + const semanage_ibendport_t **ibendport2) +{ + return sepol_ibendport_compare2(*ibendport, *ibendport2); +} + +int semanage_ibendport_key_create(semanage_handle_t *handle, + const char *ibdev_name, + int port, + semanage_ibendport_key_t **key_ptr) +{ + return sepol_ibendport_key_create(handle->sepolh, ibdev_name, port, key_ptr); +} + +int semanage_ibendport_key_extract(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + semanage_ibendport_key_t **key_ptr) +{ + return sepol_ibendport_key_extract(handle->sepolh, ibendport, key_ptr); +} + +hidden_def(semanage_ibendport_key_extract) + +void semanage_ibendport_key_free(semanage_ibendport_key_t *key) +{ + sepol_ibendport_key_free(key); +} + +hidden_def(semanage_ibendport_key_free) + +int semanage_ibendport_get_ibdev_name(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + char **ibdev_name_ptr) +{ + return sepol_ibendport_get_ibdev_name(handle->sepolh, ibendport, ibdev_name_ptr); +} + +hidden_def(semanage_ibendport_get_ibdev_name) + +int semanage_ibendport_set_ibdev_name(semanage_handle_t *handle, + semanage_ibendport_t *ibendport, + const char *ibdev_name) +{ + return sepol_ibendport_set_ibdev_name(handle->sepolh, ibendport, ibdev_name); +} + +hidden_def(semanage_ibendport_set_ibdev_name) + +int semanage_ibendport_get_port(const semanage_ibendport_t *ibendport) +{ + return sepol_ibendport_get_port(ibendport); +} + +hidden_def(semanage_ibendport_get_port) + +void semanage_ibendport_set_port(semanage_ibendport_t *ibendport, int port) +{ + sepol_ibendport_set_port(ibendport, port); +} + +hidden_def(semanage_ibendport_set_port) + +semanage_context_t *semanage_ibendport_get_con(const semanage_ibendport_t *ibendport) +{ + return sepol_ibendport_get_con(ibendport); +} + +hidden_def(semanage_ibendport_get_con) + +int semanage_ibendport_set_con(semanage_handle_t *handle, + semanage_ibendport_t *ibendport, + semanage_context_t *con) +{ + return sepol_ibendport_set_con(handle->sepolh, ibendport, con); +} + +hidden_def(semanage_ibendport_set_con) + +int semanage_ibendport_create(semanage_handle_t *handle, + semanage_ibendport_t **ibendport_ptr) +{ + return sepol_ibendport_create(handle->sepolh, ibendport_ptr); +} + +hidden_def(semanage_ibendport_create) + +int semanage_ibendport_clone(semanage_handle_t *handle, + const semanage_ibendport_t *ibendport, + semanage_ibendport_t **ibendport_ptr) +{ + return sepol_ibendport_clone(handle->sepolh, ibendport, ibendport_ptr); +} + +hidden_def(semanage_ibendport_clone) + +void semanage_ibendport_free(semanage_ibendport_t *ibendport) +{ + sepol_ibendport_free(ibendport); +} + +hidden_def(semanage_ibendport_free) + +/*key base functions */ +record_table_t SEMANAGE_IBENDPORT_RTABLE = { + .create = semanage_ibendport_create, + .key_extract = semanage_ibendport_key_extract, + .key_free = semanage_ibendport_key_free, + .clone = semanage_ibendport_clone, + .compare = semanage_ibendport_compare, + .compare2 = semanage_ibendport_compare2, + .compare2_qsort = semanage_ibendport_compare2_qsort, + .free = semanage_ibendport_free, +}; diff --git a/src/ibendports_file.c b/src/ibendports_file.c new file mode 100644 index 0000000..402c7a5 --- /dev/null +++ b/src/ibendports_file.c @@ -0,0 +1,157 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc. */ + +struct semanage_ibendport; +struct semanage_ibendport_key; +typedef struct semanage_ibendport record_t; +typedef struct semanage_ibendport_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include +#include +#include +#include +#include "ibendport_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int ibendport_print(semanage_handle_t *handle, + semanage_ibendport_t *ibendport, + FILE *str) +{ + char *con_str = NULL; + char *ibdev_name_str = NULL; + int port = semanage_ibendport_get_port(ibendport); + + if (semanage_ibendport_get_ibdev_name(handle, ibendport, &ibdev_name_str) != 0) + goto err; + + semanage_context_t *con = semanage_ibendport_get_con(ibendport); + + if (fprintf(str, "ibendportcon %s ", ibdev_name_str) < 0) + goto err; + + if (fprintf(str, "%d ", port) < 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(ibdev_name_str); + free(con_str); + return STATUS_SUCCESS; + +err: + ERR(handle, "could not print ibendport (%s) %u to stream", + ibdev_name_str, port); + free(ibdev_name_str); + free(con_str); + return STATUS_ERR; +} + +static int ibendport_parse(semanage_handle_t *handle, + parse_info_t *info, + semanage_ibendport_t *ibendport) +{ + int port; + 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, "ibendportcon") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* IB Device Name */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_ibendport_set_ibdev_name(handle, ibendport, str) < 0) + goto err; + free(str); + str = NULL; + + /* Port */ + if (parse_assert_space(handle, info) < 0) + goto err; + if (parse_fetch_int(handle, info, &port, ' ') < 0) + goto err; + semanage_ibendport_set_port(ibendport, port); + + /* 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) { + ERR(handle, "<> context is not valid for ibendport (%s: %u):\n%s", + info->filename, info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_ibendport_set_con(handle, ibendport, 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 ibendport record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* IBENDPORT RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_IBENDPORT_FILE_RTABLE = { + .parse = ibendport_parse, + .print = ibendport_print, +}; + +int ibendport_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_IBENDPORT_RTABLE, + &SEMANAGE_IBENDPORT_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void ibendport_file_dbase_release(dbase_config_t *dconfig) +{ + dbase_file_release(dconfig->dbase); +} diff --git a/src/ibendports_local.c b/src/ibendports_local.c new file mode 100644 index 0000000..8b5567d --- /dev/null +++ b/src/ibendports_local.c @@ -0,0 +1,153 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc */ + +struct semanage_ibendport; +struct semanage_ibendport_key; +typedef struct semanage_ibendport_key record_key_t; +typedef struct semanage_ibendport record_t; +#define DBASE_RECORD_DEFINED + +#include +#include +#include +#include "ibendport_internal.h" +#include "debug.h" +#include "handle.h" +#include "database.h" + +int semanage_ibendport_modify_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + const semanage_ibendport_t *data) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_ibendport_del_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_del(handle, dconfig, key); +} + +int semanage_ibendport_query_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + semanage_ibendport_t **response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_query(handle, dconfig, key, response); +} + +int semanage_ibendport_exists_local(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + int *response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_ibendport_count_local(semanage_handle_t *handle, + unsigned int *response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_count(handle, dconfig, response); +} + +int semanage_ibendport_iterate_local(semanage_handle_t *handle, + int (*handler)(const semanage_ibendport_t *record, + void *varg), void *handler_arg) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_ibendport_list_local(semanage_handle_t *handle, + semanage_ibendport_t ***records, + unsigned int *count) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle); + + return dbase_list(handle, dconfig, records, count); +} + +hidden_def(semanage_ibendport_list_local) + +int hidden semanage_ibendport_validate_local(semanage_handle_t *handle) +{ + semanage_ibendport_t **ibendports = NULL; + unsigned int nibendports = 0; + unsigned int i = 0, j = 0; + char *ibdev_name; + char *ibdev_name2; + int port; + int port2; + + /* List and sort the ibendports */ + if (semanage_ibendport_list_local(handle, &ibendports, &nibendports) < 0) + goto err; + + qsort(ibendports, nibendports, sizeof(semanage_ibendport_t *), + (int (*)(const void *, const void *)) + &semanage_ibendport_compare2_qsort); + + /* Test each ibendport */ + while (i < nibendports) { + int stop = 0; + + if (STATUS_SUCCESS != + semanage_ibendport_get_ibdev_name(handle, + ibendports[i], + &ibdev_name)) { + ERR(handle, "Couldn't get IB device name"); + goto err; + } + + port = semanage_ibendport_get_port(ibendports[i]); + + /* Find the first ibendport with matching + * ibdev_name to compare against + */ + do { + if (j == nibendports - 1) + goto next; + j++; + if (STATUS_SUCCESS != + semanage_ibendport_get_ibdev_name(handle, + ibendports[j], + &ibdev_name2)) { + ERR(handle, "Couldn't get IB device name."); + goto err; + } + port2 = semanage_ibendport_get_port(ibendports[j]); + + stop = !strcmp(ibdev_name, ibdev_name2); + } while (!stop); + + if (port == port2) { + ERR(handle, "ibendport %s/%u already exists.", + ibdev_name2, port2); + goto invalid; + } +next: + i++; + j = i; + } + + for (i = 0; i < nibendports; i++) + semanage_ibendport_free(ibendports[i]); + free(ibendports); + return STATUS_SUCCESS; + +err: + ERR(handle, "could not complete ibendports validity check"); + +invalid: + for (i = 0; i < nibendports; i++) + semanage_ibendport_free(ibendports[i]); + free(ibendports); + return STATUS_ERR; +} diff --git a/src/ibendports_policy.c b/src/ibendports_policy.c new file mode 100644 index 0000000..1347b67 --- /dev/null +++ b/src/ibendports_policy.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc */ + +struct semanage_ibendport; +struct semanage_ibendport_key; +typedef struct semanage_ibendport_key record_key_t; +typedef struct semanage_ibendport record_t; +#define DBASE_RECORD_DEFINED + +#include "ibendport_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_ibendport_query(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + semanage_ibendport_t **response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle); + + return dbase_query(handle, dconfig, key, response); +} + +int semanage_ibendport_exists(semanage_handle_t *handle, + const semanage_ibendport_key_t *key, + int *response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle); + + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_ibendport_count(semanage_handle_t *handle, + unsigned int *response) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle); + + return dbase_count(handle, dconfig, response); +} + +int semanage_ibendport_iterate(semanage_handle_t *handle, + int (*handler)(const semanage_ibendport_t *record, + void *varg), void *handler_arg) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle); + + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_ibendport_list(semanage_handle_t *handle, + semanage_ibendport_t ***records, + unsigned int *count) +{ + dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle); + + return dbase_list(handle, dconfig, records, count); +} diff --git a/src/ibendports_policydb.c b/src/ibendports_policydb.c new file mode 100644 index 0000000..1029810 --- /dev/null +++ b/src/ibendports_policydb.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 Mellanox Technologies 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. + */ + +struct semanage_ibendport; +struct semanage_ibendport_key; +typedef struct semanage_ibendport record_t; +typedef struct semanage_ibendport_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include +#include +#include "ibendport_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* IBENDPORT RECORD (SEPOL): POLICYDB extension : method table */ +record_policydb_table_t SEMANAGE_IBENDPORT_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t)sepol_ibendport_modify, + .set = NULL, + .query = (record_policydb_table_query_t)sepol_ibendport_query, + .count = (record_policydb_table_count_t)sepol_ibendport_count, + .exists = (record_policydb_table_exists_t)sepol_ibendport_exists, + .iterate = (record_policydb_table_iterate_t)sepol_ibendport_iterate, +}; + +int ibendport_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_IBENDPORT_RTABLE, + &SEMANAGE_IBENDPORT_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + + return STATUS_SUCCESS; +} + +void ibendport_policydb_dbase_release(dbase_config_t *dconfig) +{ + dbase_policydb_release(dconfig->dbase); +} diff --git a/src/ibpkey_internal.h b/src/ibpkey_internal.h new file mode 100644 index 0000000..9465bb8 --- /dev/null +++ b/src/ibpkey_internal.h @@ -0,0 +1,52 @@ +#ifndef _SEMANAGE_IBPKEY_INTERNAL_H_ +#define _SEMANAGE_IBPKEY_INTERNAL_H_ + +#include +#include +#include +#include "database.h" +#include "handle.h" +#include "dso.h" + +hidden_proto(semanage_ibpkey_create) +hidden_proto(semanage_ibpkey_compare) +hidden_proto(semanage_ibpkey_compare2) +hidden_proto(semanage_ibpkey_clone) +hidden_proto(semanage_ibpkey_free) +hidden_proto(semanage_ibpkey_key_extract) +hidden_proto(semanage_ibpkey_key_free) +hidden_proto(semanage_ibpkey_get_high) +hidden_proto(semanage_ibpkey_get_low) +hidden_proto(semanage_ibpkey_set_pkey) +hidden_proto(semanage_ibpkey_set_range) +hidden_proto(semanage_ibpkey_get_con) +hidden_proto(semanage_ibpkey_set_con) +hidden_proto(semanage_ibpkey_list_local) +hidden_proto(semanage_ibpkey_get_subnet_prefix) +hidden_proto(semanage_ibpkey_get_subnet_prefix_bytes) +hidden_proto(semanage_ibpkey_set_subnet_prefix) +hidden_proto(semanage_ibpkey_set_subnet_prefix_bytes) + +/* PKEY RECORD: method table */ +extern record_table_t SEMANAGE_IBPKEY_RTABLE; + +extern int ibpkey_file_dbase_init(semanage_handle_t *handle, + const char *path_ro, + const char *path_rw, + dbase_config_t *dconfig); + +extern void ibpkey_file_dbase_release(dbase_config_t *dconfig); + +extern int ibpkey_policydb_dbase_init(semanage_handle_t *handle, + dbase_config_t *dconfig); + +extern void ibpkey_policydb_dbase_release(dbase_config_t *dconfig); + +extern int hidden semanage_ibpkey_validate_local(semanage_handle_t *handle); + +/* ==== Internal (to ibpkeys) API === */ + +hidden int semanage_ibpkey_compare2_qsort(const semanage_ibpkey_t **ibpkey, + const semanage_ibpkey_t **ibpkey2); + +#endif diff --git a/src/ibpkey_record.c b/src/ibpkey_record.c new file mode 100644 index 0000000..ca5bc76 --- /dev/null +++ b/src/ibpkey_record.c @@ -0,0 +1,182 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc. */ + +/* Object: semanage_ibpkey_t (Infiniband Pkey) + * Object: semanage_ibpkey_key_t (Infiniband Pkey Key) + * Implements: record_t (Database Record) + * Implements: record_key_t (Database Record Key) + */ + +#include +#include + +typedef sepol_context_t semanage_context_t; +typedef sepol_ibpkey_t semanage_ibpkey_t; +typedef sepol_ibpkey_key_t semanage_ibpkey_key_t; +#define _SEMANAGE_IBPKEY_DEFINED_ +#define _SEMANAGE_CONTEXT_DEFINED_ + +typedef semanage_ibpkey_t record_t; +typedef semanage_ibpkey_key_t record_key_t; +#define DBASE_RECORD_DEFINED + +#include "ibpkey_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_ibpkey_compare(const semanage_ibpkey_t *ibpkey, + const semanage_ibpkey_key_t *key) +{ + return sepol_ibpkey_compare(ibpkey, key); +} + +hidden_def(semanage_ibpkey_compare) + +int semanage_ibpkey_compare2(const semanage_ibpkey_t *ibpkey, + const semanage_ibpkey_t *ibpkey2) +{ + return sepol_ibpkey_compare2(ibpkey, ibpkey2); +} + +hidden_def(semanage_ibpkey_compare2) + +hidden int semanage_ibpkey_compare2_qsort(const semanage_ibpkey_t **ibpkey, + const semanage_ibpkey_t **ibpkey2) +{ + return sepol_ibpkey_compare2(*ibpkey, *ibpkey2); +} + +int semanage_ibpkey_key_create(semanage_handle_t *handle, + const char *subnet_prefix, + int low, int high, + semanage_ibpkey_key_t **key_ptr) +{ + return sepol_ibpkey_key_create(handle->sepolh, subnet_prefix, low, high, key_ptr); +} + +int semanage_ibpkey_key_extract(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + semanage_ibpkey_key_t **key_ptr) +{ + return sepol_ibpkey_key_extract(handle->sepolh, ibpkey, key_ptr); +} + +hidden_def(semanage_ibpkey_key_extract) + +void semanage_ibpkey_key_free(semanage_ibpkey_key_t *key) +{ + sepol_ibpkey_key_free(key); +} + +hidden_def(semanage_ibpkey_key_free) + +int semanage_ibpkey_get_subnet_prefix(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + char **subnet_prefix_ptr) +{ + return sepol_ibpkey_get_subnet_prefix(handle->sepolh, ibpkey, subnet_prefix_ptr); +} + +hidden_def(semanage_ibpkey_get_subnet_prefix) + +uint64_t semanage_ibpkey_get_subnet_prefix_bytes(const semanage_ibpkey_t *ibpkey) +{ + return sepol_ibpkey_get_subnet_prefix_bytes(ibpkey); +} + +hidden_def(semanage_ibpkey_get_subnet_prefix_bytes) + +int semanage_ibpkey_set_subnet_prefix(semanage_handle_t *handle, + semanage_ibpkey_t *ibpkey, + const char *subnet_prefix) +{ + return sepol_ibpkey_set_subnet_prefix(handle->sepolh, ibpkey, subnet_prefix); +} + +hidden_def(semanage_ibpkey_set_subnet_prefix) + +void semanage_ibpkey_set_subnet_prefix_bytes(semanage_ibpkey_t *ibpkey, + uint64_t subnet_prefix) +{ + return sepol_ibpkey_set_subnet_prefix_bytes(ibpkey, subnet_prefix); +} + +hidden_def(semanage_ibpkey_set_subnet_prefix_bytes) + +int semanage_ibpkey_get_low(const semanage_ibpkey_t *ibpkey) +{ + return sepol_ibpkey_get_low(ibpkey); +} + +hidden_def(semanage_ibpkey_get_low) + +int semanage_ibpkey_get_high(const semanage_ibpkey_t *ibpkey) +{ + return sepol_ibpkey_get_high(ibpkey); +} + +hidden_def(semanage_ibpkey_get_high) + +void semanage_ibpkey_set_pkey(semanage_ibpkey_t *ibpkey, int ibpkey_num) +{ + sepol_ibpkey_set_pkey(ibpkey, ibpkey_num); +} + +hidden_def(semanage_ibpkey_set_pkey) + +void semanage_ibpkey_set_range(semanage_ibpkey_t *ibpkey, int low, int high) +{ + sepol_ibpkey_set_range(ibpkey, low, high); +} + +hidden_def(semanage_ibpkey_set_range) + +semanage_context_t *semanage_ibpkey_get_con(const semanage_ibpkey_t *ibpkey) +{ + return sepol_ibpkey_get_con(ibpkey); +} + +hidden_def(semanage_ibpkey_get_con) + +int semanage_ibpkey_set_con(semanage_handle_t *handle, + semanage_ibpkey_t *ibpkey, semanage_context_t *con) +{ + return sepol_ibpkey_set_con(handle->sepolh, ibpkey, con); +} + +hidden_def(semanage_ibpkey_set_con) + +int semanage_ibpkey_create(semanage_handle_t *handle, + semanage_ibpkey_t **ibpkey_ptr) +{ + return sepol_ibpkey_create(handle->sepolh, ibpkey_ptr); +} + +hidden_def(semanage_ibpkey_create) + +int semanage_ibpkey_clone(semanage_handle_t *handle, + const semanage_ibpkey_t *ibpkey, + semanage_ibpkey_t **ibpkey_ptr) +{ + return sepol_ibpkey_clone(handle->sepolh, ibpkey, ibpkey_ptr); +} + +hidden_def(semanage_ibpkey_clone) + +void semanage_ibpkey_free(semanage_ibpkey_t *ibpkey) +{ + sepol_ibpkey_free(ibpkey); +} + +hidden_def(semanage_ibpkey_free) + +/* key base functions */ +record_table_t SEMANAGE_IBPKEY_RTABLE = { + .create = semanage_ibpkey_create, + .key_extract = semanage_ibpkey_key_extract, + .key_free = semanage_ibpkey_key_free, + .clone = semanage_ibpkey_clone, + .compare = semanage_ibpkey_compare, + .compare2 = semanage_ibpkey_compare2, + .compare2_qsort = semanage_ibpkey_compare2_qsort, + .free = semanage_ibpkey_free, +}; diff --git a/src/ibpkeys_file.c b/src/ibpkeys_file.c new file mode 100644 index 0000000..ceaea7a --- /dev/null +++ b/src/ibpkeys_file.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc. */ + +struct semanage_ibpkey; +struct semanage_ibpkey_key; +typedef struct semanage_ibpkey record_t; +typedef struct semanage_ibpkey_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_file; +typedef struct dbase_file dbase_t; +#define DBASE_DEFINED + +#include +#include +#include +#include +#include "ibpkey_internal.h" +#include "context_internal.h" +#include "database_file.h" +#include "parse_utils.h" +#include "debug.h" + +static int ibpkey_print(semanage_handle_t *handle, + semanage_ibpkey_t *ibpkey, FILE *str) +{ + char *con_str = NULL; + char *subnet_prefix_str = NULL; + + int low = semanage_ibpkey_get_low(ibpkey); + int high = semanage_ibpkey_get_high(ibpkey); + + if (semanage_ibpkey_get_subnet_prefix(handle, ibpkey, &subnet_prefix_str) != 0) + goto err; + + semanage_context_t *con = semanage_ibpkey_get_con(ibpkey); + + if (fprintf(str, "ibpkeycon %s ", subnet_prefix_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(subnet_prefix_str); + free(con_str); + return STATUS_SUCCESS; + +err: + ERR(handle, "could not print ibpkey range (%s) %u - %u to stream", + subnet_prefix_str, low, high); + free(subnet_prefix_str); + free(con_str); + return STATUS_ERR; +} + +static int ibpkey_parse(semanage_handle_t *handle, + parse_info_t *info, semanage_ibpkey_t *ibpkey) +{ + 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, "ibpkeycon") < 0) + goto err; + if (parse_assert_space(handle, info) < 0) + goto err; + + /* Subnet Prefix */ + if (parse_fetch_string(handle, info, &str, ' ') < 0) + goto err; + if (semanage_ibpkey_set_subnet_prefix(handle, ibpkey, str) < 0) + goto err; + free(str); + str = NULL; + + /* Range/Pkey */ + 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 ibpkey 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_ibpkey_set_range(ibpkey, low, high); + } else { + semanage_ibpkey_set_pkey(ibpkey, low); + } + /* Pkey 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) { + ERR(handle, "<> context is not valid for ibpkeys (%s: %u):\n%s", + info->filename, + info->lineno, info->orig_line); + goto err; + } + free(str); + str = NULL; + + if (semanage_ibpkey_set_con(handle, ibpkey, 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 ibpkey record"); + free(str); + semanage_context_free(con); + parse_dispose_line(info); + return STATUS_ERR; +} + +/* IBPKEY RECORD: FILE extension: method table */ +record_file_table_t SEMANAGE_IBPKEY_FILE_RTABLE = { + .parse = ibpkey_parse, + .print = ibpkey_print, +}; + +int ibpkey_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_IBPKEY_RTABLE, + &SEMANAGE_IBPKEY_FILE_RTABLE, &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_FILE_DTABLE; + return STATUS_SUCCESS; +} + +void ibpkey_file_dbase_release(dbase_config_t *dconfig) +{ + dbase_file_release(dconfig->dbase); +} diff --git a/src/ibpkeys_local.c b/src/ibpkeys_local.c new file mode 100644 index 0000000..e194ee0 --- /dev/null +++ b/src/ibpkeys_local.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc. */ + +struct semanage_ibpkey; +struct semanage_ibpkey_key; +typedef struct semanage_ibpkey_key record_key_t; +typedef struct semanage_ibpkey record_t; +#define DBASE_RECORD_DEFINED + +#include +#include +#include +#include "ibpkey_internal.h" +#include "debug.h" +#include "handle.h" +#include "database.h" + +int semanage_ibpkey_modify_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + const semanage_ibpkey_t *data) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_modify(handle, dconfig, key, data); +} + +int semanage_ibpkey_del_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_del(handle, dconfig, key); +} + +int semanage_ibpkey_query_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + semanage_ibpkey_t **response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_query(handle, dconfig, key, response); +} + +int semanage_ibpkey_exists_local(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + int *response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_ibpkey_count_local(semanage_handle_t *handle, + unsigned int *response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_count(handle, dconfig, response); +} + +int semanage_ibpkey_iterate_local(semanage_handle_t *handle, + int (*handler)(const semanage_ibpkey_t *record, + void *varg), void *handler_arg) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_ibpkey_list_local(semanage_handle_t *handle, + semanage_ibpkey_t ***records, unsigned int *count) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle); + + return dbase_list(handle, dconfig, records, count); +} + +hidden_def(semanage_ibpkey_list_local) + +int hidden semanage_ibpkey_validate_local(semanage_handle_t *handle) +{ + semanage_ibpkey_t **ibpkeys = NULL; + unsigned int nibpkeys = 0; + unsigned int i = 0, j = 0; + uint64_t subnet_prefix; + uint64_t subnet_prefix2; + char *subnet_prefix_str; + char *subnet_prefix_str2; + int low, high; + int low2, high2; + + /* List and sort the ibpkeys */ + if (semanage_ibpkey_list_local(handle, &ibpkeys, &nibpkeys) < 0) + goto err; + + qsort(ibpkeys, nibpkeys, sizeof(semanage_ibpkey_t *), + (int (*)(const void *, const void *)) + &semanage_ibpkey_compare2_qsort); + + /* Test each ibpkey for overlap */ + while (i < nibpkeys) { + if (STATUS_SUCCESS != semanage_ibpkey_get_subnet_prefix(handle, + ibpkeys[i], + &subnet_prefix_str)) { + ERR(handle, "Couldn't get subnet prefix string"); + goto err; + } + + subnet_prefix = semanage_ibpkey_get_subnet_prefix_bytes(ibpkeys[i]); + low = semanage_ibpkey_get_low(ibpkeys[i]); + high = semanage_ibpkey_get_high(ibpkeys[i]); + + /* Find the first ibpkey with matching + * subnet_prefix to compare against + */ + do { + if (j == nibpkeys - 1) + goto next; + j++; + + if (STATUS_SUCCESS != + semanage_ibpkey_get_subnet_prefix(handle, + ibpkeys[j], + &subnet_prefix_str2)) { + ERR(handle, "Couldn't get subnet prefix string"); + goto err; + } + subnet_prefix2 = semanage_ibpkey_get_subnet_prefix_bytes(ibpkeys[j]); + low2 = semanage_ibpkey_get_low(ibpkeys[j]); + high2 = semanage_ibpkey_get_high(ibpkeys[j]); + } while (subnet_prefix != subnet_prefix2); + + /* Overlap detected */ + if (low2 <= high) { + ERR(handle, "ibpkey overlap between ranges " + "(%s) %u - %u <--> (%s) %u - %u.", + subnet_prefix_str, low, high, + subnet_prefix_str2, low2, high2); + goto invalid; + } + + /* If closest ibpkey of matching subnet prefix doesn't overlap + * with test ibpkey, neither do the rest of them, because that's + * how the sort function works on ibpkeys - lower bound + * ibpkeys come first + */ +next: + i++; + j = i; + } + + for (i = 0; i < nibpkeys; i++) + semanage_ibpkey_free(ibpkeys[i]); + free(ibpkeys); + return STATUS_SUCCESS; + +err: + ERR(handle, "could not complete ibpkeys validity check"); + +invalid: + for (i = 0; i < nibpkeys; i++) + semanage_ibpkey_free(ibpkeys[i]); + free(ibpkeys); + return STATUS_ERR; +} diff --git a/src/ibpkeys_policy.c b/src/ibpkeys_policy.c new file mode 100644 index 0000000..0956230 --- /dev/null +++ b/src/ibpkeys_policy.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2017 Mellanox Technologies Inc. */ + +struct semanage_ibpkey; +struct semanage_ibpkey_key; +typedef struct semanage_ibpkey_key record_key_t; +typedef struct semanage_ibpkey record_t; +#define DBASE_RECORD_DEFINED + +#include "ibpkey_internal.h" +#include "handle.h" +#include "database.h" + +int semanage_ibpkey_query(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, + semanage_ibpkey_t **response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle); + + return dbase_query(handle, dconfig, key, response); +} + +int semanage_ibpkey_exists(semanage_handle_t *handle, + const semanage_ibpkey_key_t *key, int *response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle); + + return dbase_exists(handle, dconfig, key, response); +} + +int semanage_ibpkey_count(semanage_handle_t *handle, unsigned int *response) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle); + + return dbase_count(handle, dconfig, response); +} + +int semanage_ibpkey_iterate(semanage_handle_t *handle, + int (*handler)(const semanage_ibpkey_t *record, + void *varg), void *handler_arg) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle); + + return dbase_iterate(handle, dconfig, handler, handler_arg); +} + +int semanage_ibpkey_list(semanage_handle_t *handle, + semanage_ibpkey_t ***records, unsigned int *count) +{ + dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle); + + return dbase_list(handle, dconfig, records, count); +} diff --git a/src/ibpkeys_policydb.c b/src/ibpkeys_policydb.c new file mode 100644 index 0000000..8d73cf6 --- /dev/null +++ b/src/ibpkeys_policydb.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 Mellanox Technologies 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. + */ + +struct semanage_ibpkey; +struct semanage_ibpkey_key; +typedef struct semanage_ibpkey record_t; +typedef struct semanage_ibpkey_key record_key_t; +#define DBASE_RECORD_DEFINED + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include +#include +#include "ibpkey_internal.h" +#include "debug.h" +#include "database_policydb.h" +#include "semanage_store.h" + +/* PKEY RECORD (SEPOL): POLICYDB extension : method table */ +record_policydb_table_t SEMANAGE_IBPKEY_POLICYDB_RTABLE = { + .add = NULL, + .modify = (record_policydb_table_modify_t)sepol_ibpkey_modify, + .set = NULL, + .query = (record_policydb_table_query_t)sepol_ibpkey_query, + .count = (record_policydb_table_count_t)sepol_ibpkey_count, + .exists = (record_policydb_table_exists_t)sepol_ibpkey_exists, + .iterate = (record_policydb_table_iterate_t)sepol_ibpkey_iterate, +}; + +int ibpkey_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_IBPKEY_RTABLE, + &SEMANAGE_IBPKEY_POLICYDB_RTABLE, + &dconfig->dbase) < 0) + return STATUS_ERR; + + dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE; + + return STATUS_SUCCESS; +} + +void ibpkey_policydb_dbase_release(dbase_config_t *dconfig) +{ + dbase_policydb_release(dconfig->dbase); +} diff --git a/src/iface_internal.h b/src/iface_internal.h new file mode 100644 index 0000000..1f67836 --- /dev/null +++ b/src/iface_internal.h @@ -0,0 +1,40 @@ +#ifndef _SEMANAGE_IFACE_INTERNAL_H_ +#define _SEMANAGE_IFACE_INTERNAL_H_ + +#include +#include +#include +#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/src/iface_record.c b/src/iface_record.c new file mode 100644 index 0000000..e7d72d7 --- /dev/null +++ b/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 +#include + +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/src/interfaces_file.c b/src/interfaces_file.c new file mode 100644 index 0000000..1478af9 --- /dev/null +++ b/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 +#include +#include +#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, "<> 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, "<> 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/src/interfaces_local.c b/src/interfaces_local.c new file mode 100644 index 0000000..acf6851 --- /dev/null +++ b/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/src/interfaces_policy.c b/src/interfaces_policy.c new file mode 100644 index 0000000..7f9b2ef --- /dev/null +++ b/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/src/interfaces_policydb.c b/src/interfaces_policydb.c new file mode 100644 index 0000000..552ce7d --- /dev/null +++ b/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 +#include +#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/src/libsemanage.map b/src/libsemanage.map new file mode 100644 index 0000000..0203669 --- /dev/null +++ b/src/libsemanage.map @@ -0,0 +1,65 @@ +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_ibpkey_*; + semanage_ibendport_*; + 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; +} LIBSEMANAGE_1.0; diff --git a/src/libsemanage.pc.in b/src/libsemanage.pc.in new file mode 100644 index 0000000..43681dd --- /dev/null +++ b/src/libsemanage.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: libsemanage +Description: SELinux management library +Version: @VERSION@ +URL: http://userspace.selinuxproject.org/ +Requires.private: libselinux libsepol +Libs: -L${libdir} -lsemanage +Libs.private: -lbz2 +Cflags: -I${includedir} diff --git a/src/module_internal.h b/src/module_internal.h new file mode 100644 index 0000000..c99f6c2 --- /dev/null +++ b/src/module_internal.h @@ -0,0 +1,27 @@ +#ifndef _SEMANAGE_MODULE_INTERNAL_H_ +#define _SEMANAGE_MODULE_INTERNAL_H_ + +#include +#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/src/modules.c b/src/modules.c new file mode 100644 index 0000000..62af101 --- /dev/null +++ b/src/modules.c @@ -0,0 +1,1148 @@ +/* Author: Joshua Brindle + * Caleb Case + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"; + /* FALLTHRU */ + case SEMANAGE_MODULE_PATH_CIL: + if (file == NULL) file = "cil"; + /* FALLTHRU */ + 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/src/modules.h b/src/modules.h new file mode 100644 index 0000000..8a5c01f --- /dev/null +++ b/src/modules.h @@ -0,0 +1,112 @@ +/* Author: Joshua Brindle + * Jason Tang + * Caleb Case + * + * 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 + +#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/src/node_internal.h b/src/node_internal.h new file mode 100644 index 0000000..5817560 --- /dev/null +++ b/src/node_internal.h @@ -0,0 +1,55 @@ +#ifndef _SEMANAGE_NODE_INTERNAL_H_ +#define _SEMANAGE_NODE_INTERNAL_H_ + +#include +#include +#include +#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/src/node_record.c b/src/node_record.c new file mode 100644 index 0000000..5368cee --- /dev/null +++ b/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 +#include +#include + +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/src/nodes_file.c b/src/nodes_file.c new file mode 100644 index 0000000..f6c8895 --- /dev/null +++ b/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 +#include +#include +#include +#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, "<> 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/src/nodes_local.c b/src/nodes_local.c new file mode 100644 index 0000000..93af450 --- /dev/null +++ b/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/src/nodes_policy.c b/src/nodes_policy.c new file mode 100644 index 0000000..dc71cc8 --- /dev/null +++ b/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/src/nodes_policydb.c b/src/nodes_policydb.c new file mode 100644 index 0000000..7224f00 --- /dev/null +++ b/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 +#include +#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/src/parse_utils.c b/src/parse_utils.c new file mode 100644 index 0000000..4fb54fc --- /dev/null +++ b/src/parse_utils.c @@ -0,0 +1,307 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#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/src/parse_utils.h b/src/parse_utils.h new file mode 100644 index 0000000..0f33486 --- /dev/null +++ b/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 +#include + +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/src/policy.h b/src/policy.h new file mode 100644 index 0000000..f127156 --- /dev/null +++ b/src/policy.h @@ -0,0 +1,106 @@ +/* Author: Joshua Brindle + * Jason Tang + * + * 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/src/policy_components.c b/src/policy_components.c new file mode 100644 index 0000000..896ac51 --- /dev/null +++ b/src/policy_components.c @@ -0,0 +1,246 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +#include +#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}, + + {semanage_ibpkey_dbase_local(handle), + semanage_ibpkey_dbase_policy(handle), MODE_MODIFY}, + + {semanage_ibendport_dbase_local(handle), + semanage_ibendport_dbase_policy(handle), MODE_MODIFY}, + }; + 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), + semanage_ibpkey_dbase_local(handle), + semanage_ibendport_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/src/port_internal.h b/src/port_internal.h new file mode 100644 index 0000000..ebd2bc8 --- /dev/null +++ b/src/port_internal.h @@ -0,0 +1,51 @@ +#ifndef _SEMANAGE_PORT_INTERNAL_H_ +#define _SEMANAGE_PORT_INTERNAL_H_ + +#include +#include +#include +#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/src/port_record.c b/src/port_record.c new file mode 100644 index 0000000..b878ca7 --- /dev/null +++ b/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 +#include + +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/src/ports_file.c b/src/ports_file.c new file mode 100644 index 0000000..4738d46 --- /dev/null +++ b/src/ports_file.c @@ -0,0 +1,191 @@ +/* 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 +#include +#include +#include +#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 if (!strcasecmp(str, "dccp")) + semanage_port_set_proto(port, SEMANAGE_PROTO_DCCP); + else if (!strcasecmp(str, "sctp")) + semanage_port_set_proto(port, SEMANAGE_PROTO_SCTP); + 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, "<> 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/src/ports_local.c b/src/ports_local.c new file mode 100644 index 0000000..ffd5a83 --- /dev/null +++ b/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 +#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/src/ports_policy.c b/src/ports_policy.c new file mode 100644 index 0000000..1bcd3fa --- /dev/null +++ b/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/src/ports_policydb.c b/src/ports_policydb.c new file mode 100644 index 0000000..37d7deb --- /dev/null +++ b/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 +#include +#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/src/pywrap-test.py b/src/pywrap-test.py new file mode 100644 index 0000000..5ac48f4 --- /dev/null +++ b/src/pywrap-test.py @@ -0,0 +1,1298 @@ +#!/usr/bin/env python +from __future__ import print_function + +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: %s" % trans_cnt) + print("Module list size: %s" % mlist_size) + if self.verbose: + print("List reference: %s" % 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: %s" % module) + print("Module name: %s" % 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): %s" % 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: %s" % seuser) + print("seuser name: %s" % semanage.semanage_seuser_get_name(seuser)) + print(" seuser mls range: %s" % semanage.semanage_seuser_get_mlsrange(seuser)) + print(" seuser sename: %s" % 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): %s" % 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: %s" % user) + print("User name: %s" % semanage.semanage_user_get_name(user)) + print(" User labeling prefix: %s" % semanage.semanage_user_get_prefix(user)) + print(" User mls level: %s" % semanage.semanage_user_get_mlslevel(user)) + print(" User mls range: %s" % semanage.semanage_user_get_mlsrange(user)) + print(" User number of roles: %s" % 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(" %s" % 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): %s" % 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: %s" % 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: %s %s Context: %s" % (range_str, proto_str, 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): %s" % 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: %s" % 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 = "<>" + else: + (rc, con_str) = semanage.semanage_context_to_string(sh, con) + if rc < 0: + con_str = "" + print("File Expr: %s [%s] Context: %s" % (expr, type_str, 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): %s" % 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: %s" % 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: %s Context: %s Message Context: %s" % (name, if_con_str, 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): %s" % 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: %s" % pbool) + name = semanage.semanage_bool_get_name(pbool) + value = semanage.semanage_bool_get_value(pbool) + print("Boolean: %s Value: %s" % (name, 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): %s" % 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: %s" % abool) + name = semanage.semanage_bool_get_name(abool) + value = semanage.semanage_bool_get_value(abool) + print("Active Boolean: %s Value: %s" % (name, 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): %s" % 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: %s" % 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: %s/%s (%s) Context: %s" % (addr, mask, proto_str, 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s-%s" % (low, high)) + + semanage.semanage_port_set_proto(port, semanage.SEMANAGE_PROTO_TCP) + if self.verbose: + print("SEPort protocol set: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % semanage.semanage_bool_get_name(pbool)) + + semanage.semanage_bool_set_value(pbool, 0) + if self.verbose: + print("SEbool value set: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % 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): %s" % 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: %s" % semanage.semanage_bool_get_name(abool)) + + semanage.semanage_bool_set_value(abool, 0) + if self.verbose: + print("SEbool value set: %s" % 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): %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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: %s" % 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): %s" % 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): %s" % 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): %s" % 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: %s" % 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: %s" % status) + + status = semanage.semanage_commit(sh) + if status < 0: + raise Error("Could not commit reset transaction") + print("Commit status (transaction number): %s" % 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 as 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 as err: + print(err.msg, file=sys.stderr) + except Status as err: + print(err.msg, file=sys.stderr) + except Error as err: + print(err.msg, file=sys.stderr) + + return 2 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/semanage.conf b/src/semanage.conf new file mode 100644 index 0000000..dc8d46b --- /dev/null +++ b/src/semanage.conf @@ -0,0 +1,41 @@ +# Authors: Jason Tang +# +# 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 . 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/src/semanage_conf.h b/src/semanage_conf.h new file mode 100644 index 0000000..c99ac8c --- /dev/null +++ b/src/semanage_conf.h @@ -0,0 +1,70 @@ +/* Authors: Jason Tang + * + * 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 +#include +#include + +/* 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/src/semanage_store.c b/src/semanage_store.c new file mode 100644 index 0000000..733df8d --- /dev/null +++ b/src/semanage_store.c @@ -0,0 +1,3021 @@ +/* Authors: Karl MacMillan + * Joshua Brindle + * Jason Tang + * Christopher Ashworth + * Chris PeBenito + * Caleb Case + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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", + "/policy.linked", + "/homedir_template", + "/file_contexts.template", + "/commit_num", + "/pkeys.local", + "/ibendports.local", + "/ports.local", + "/interfaces.local", + "/nodes.local", + "/booleans.local", + "/seusers.local", + "/seusers.linked", + "/users.local", + "/users_extra.local", + "/users_extra.linked", + "/users_extra", + "/disable_dontaudit", + "/preserve_tunables", + "/modules/disabled", + "/policy.kern", + "/file_contexts.local", + "/file_contexts.homedirs", + "/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; + } + + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC]) < 0) { + 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; + } + + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_HOMEDIRS_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC_HOMEDIRS]) < 0) { + 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; + } + + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_LOCAL_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC_LOCAL]) < 0) { + 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; + struct stat sb; + + 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 (stat(semanage_conf, &sb) != 0 && errno == ENOENT) { + 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; + const char *path = semanage_files[SEMANAGE_ROOT]; + int fd; + mode_t mask; + + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + mask = umask(0077); + if (mkdir(path, S_IRWXU) == -1) { + umask(mask); + ERR(sh, "Could not create module store at %s.", + path); + return -2; + } + umask(mask); + } else { + if (create) + ERR(sh, + "Could not read from module store at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode)) { + ERR(sh, + "Module store at %s is not a directory.", + path); + return -1; + } + } + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL); + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + mask = umask(0077); + if (mkdir(path, S_IRWXU) == -1) { + umask(mask); + ERR(sh, + "Could not create module store, active subdirectory at %s.", + path); + return -2; + } + umask(mask); + } else { + ERR(sh, + "Could not read from module store, active subdirectory at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode)) { + ERR(sh, + "Module store active subdirectory at %s is not a directory.", + path); + return -1; + } + } + path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + mask = umask(0077); + if (mkdir(path, S_IRWXU) == -1) { + umask(mask); + ERR(sh, + "Could not create module store, active modules subdirectory at %s.", + path); + return -2; + } + umask(mask); + } else { + ERR(sh, + "Could not read from module store, active modules subdirectory at %s.", + path); + return -1; + } + } else { + if (!S_ISDIR(sb.st_mode)) { + ERR(sh, + "Module store active modules subdirectory at %s is not a directory.", + path); + return -1; + } + } + path = semanage_files[SEMANAGE_READ_LOCK]; + if (stat(path, &sb) == -1) { + if (errno == ENOENT && create) { + mask = umask(0077); + if ((fd = creat(path, S_IRUSR | S_IWUSR)) == -1) { + umask(mask); + ERR(sh, "Could not create lock file at %s.", + path); + return -2; + } + umask(mask); + close(fd); + } else { + ERR(sh, "Could not read lock file at %s.", path); + return -1; + } + } else { + if (!S_ISREG(sb.st_mode)) { + ERR(sh, "Object at %s is not a lock file.", 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, + bool syncrequired) +{ + 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) != amount_read) { + if (errno) + errsv = errno; + else + errsv = EIO; + retval = -1; + } + } + if (amount_read < 0) { + errsv = errno; + retval = -1; + } + close(in); + if (syncrequired && fsync(out) < 0) { + errsv = errno; + retval = -1; + } + 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]; + mode_t mask; + + 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) { + mask = umask(0077); + if (mkdir(dst, S_IRWXU) != 0) { + umask(mask); + fprintf(stderr, "Could not create %s: %s\n", dst, strerror(errno)); + goto cleanup; + } + umask(mask); + } + + 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)) { + mask = umask(0077); + if (mkdir(path2, 0700) == -1 || + semanage_copy_dir_flags(path, path2, flag) == -1) { + umask(mask); + goto cleanup; + } + umask(mask); + } else if (S_ISREG(sb.st_mode) && flag == 1) { + mask = umask(0077); + if (semanage_copy_file(path, path2, sb.st_mode, + false) < 0) { + umask(mask); + goto cleanup; + } + umask(mask); + } + } + 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[PATH_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; + mode_t mask; + + /* check if directory already exists */ + if (stat(path, &sb) != 0) { + /* make the modules directory */ + mask = umask(0077); + if (mkdir(path, S_IRWXU) != 0) { + umask(mask); + ERR(sh, "Cannot make directory at %s", path); + status = -1; + goto cleanup; + + } + umask(mask); + } + 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; + mode_t mask; + + 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; + } + } + + mask = umask(0077); + if (mkdir(sandbox, S_IRWXU) == -1 || + semanage_copy_dir(semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL), + sandbox) == -1) { + umask(mask); + ERR(sh, "Could not copy files to sandbox %s.", sandbox); + goto cleanup; + } + umask(mask); + 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."); + return -1; + } + + 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; i++) { + 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; + char *new_s; + + if (t == NULL) { + return s; + } + t_len = strlen(t); + 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); + if (rc) + goto cleanup; + 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); + if (rc) + goto cleanup; + 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; + struct stat sb; + + if (stat(path, &sb) < 0) { + if (errno != ENOENT) { + ERR(sh, "Unable to access %s: %s\n", path, strerror(errno)); + return -1; + } + + 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; +} + +static int semanage_validate_and_compile_fcontexts(semanage_handle_t * sh) +{ + int status = -1; + + if (sh->do_check_contexts) { + int ret; + ret = semanage_exec_prog( + sh, + sh->conf->setfiles, + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_KERNEL), + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FC)); + if (ret != 0) { + ERR(sh, "setfiles returned error code %d.", ret); + goto cleanup; + } + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS)) != 0) { + goto cleanup; + } + + status = 0; +cleanup: + return status; +} + +/* 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; + + if (strlen(dst) >= sizeof(fn)) { + ERR(sh, "Unable to compose the final paths."); + status = -1; + goto cleanup; + } + strcpy(fn, dst); + ret = semanage_mkpath(sh, dirname(fn)); + if (ret < 0) { + goto cleanup; + } + + ret = semanage_copy_file(src, dst, sh->conf->file_mode, + true); + 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: + 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; + if (semanage_remove_directory(backup) != 0) { + ERR(sh, "Could not delete previous directory %s.", backup); + retval = -1; + 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 (semanage_validate_and_compile_fcontexts(sh) < 0) + 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 (linked or kernel) + */ +int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in, + enum semanage_sandbox_defs file) +{ + + 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, file)) == 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 policy to the sandbox (linked or kernel) + */ +int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out, + enum semanage_sandbox_defs file) +{ + + int retval = STATUS_ERR; + const char *kernel_filename = NULL; + struct sepol_policy_file *pf = NULL; + FILE *outfile = NULL; + mode_t mask = umask(0077); + + if ((kernel_filename = + semanage_path(SEMANAGE_TMP, file)) == 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); + } + umask(mask); + 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_final_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/src/semanage_store.h b/src/semanage_store.h new file mode 100644 index 0000000..b9ec566 --- /dev/null +++ b/src/semanage_store.h @@ -0,0 +1,169 @@ +/* Authors: Karl MacMillan + * Joshua Brindle + * Jason Tang + * Christopher Ashworth + * + * 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 +#include +#include +#include +#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_IBPKEYS_LOCAL, + SEMANAGE_IBENDPORTS_LOCAL, + SEMANAGE_PORTS_LOCAL, + SEMANAGE_INTERFACES_LOCAL, + SEMANAGE_NODES_LOCAL, + SEMANAGE_BOOLEANS_LOCAL, + SEMANAGE_SEUSERS_LOCAL, + SEMANAGE_SEUSERS_LINKED, + SEMANAGE_USERS_BASE_LOCAL, + SEMANAGE_USERS_EXTRA_LOCAL, + SEMANAGE_USERS_EXTRA_LINKED, + SEMANAGE_USERS_EXTRA, + SEMANAGE_DISABLE_DONTAUDIT, + SEMANAGE_PRESERVE_TUNABLES, + SEMANAGE_MODULES_DISABLED, + SEMANAGE_STORE_KERNEL, + SEMANAGE_STORE_FC_LOCAL, + SEMANAGE_STORE_FC_HOMEDIRS, + 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_BIN, + SEMANAGE_FC_HOMEDIRS, + SEMANAGE_FC_HOMEDIRS_BIN, + SEMANAGE_FC_LOCAL, + SEMANAGE_FC_LOCAL_BIN, + 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, + enum semanage_sandbox_defs file); + +int semanage_write_policydb(semanage_handle_t * sh, + sepol_policydb_t * policydb, + enum semanage_sandbox_defs file); + +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, + bool syncrequired); + +#endif diff --git a/src/semanageswig.i b/src/semanageswig.i new file mode 100644 index 0000000..ebf39cf --- /dev/null +++ b/src/semanageswig.i @@ -0,0 +1,57 @@ +/* Author: Spencer Shimko + * + * 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/ibpkey_record.h" +%include "../include/semanage/ibpkeys_local.h" +%include "../include/semanage/ibpkeys_policy.h" +%include "../include/semanage/ibendport_record.h" +%include "../include/semanage/ibendports_local.h" +%include "../include/semanage/ibendports_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/src/semanageswig_python.i b/src/semanageswig_python.i new file mode 100644 index 0000000..8604b8a --- /dev/null +++ b/src/semanageswig_python.i @@ -0,0 +1,571 @@ +/* Author: Spencer Shimko + * + * 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 + #include + #include + + #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 +/* 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 +/* 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; +} + +/** ibpkey typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_ibpkey_t *** parameter */ +%typemap(in, numinputs=0) semanage_ibpkey_t ***(semanage_ibpkey_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_ibpkey_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_ibpkey, + (void (*) (void*)) &semanage_ibpkey_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_ibpkey_t **(semanage_ibpkey_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_ibpkey_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_ibpkey_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_ibpkey_key_t **(semanage_ibpkey_key_t *temp=NULL) { + $1 = &temp; +} + +/** ibendport typemaps **/ + +/* the wrapper will setup this parameter for passing... the resulting python functions + will not take the semanage_ibendport_t *** parameter */ +%typemap(in, numinputs=0) semanage_ibendport_t ***(semanage_ibendport_t **temp=NULL) { + $1 = &temp; +} + +%typemap(argout) ( + semanage_handle_t* handle, + semanage_ibendport_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_ibendport, + (void (*) (void*)) &semanage_ibendport_free, &plist) < 0) + $result = SWIG_From_int(STATUS_ERR); + else + $result = SWIG_Python_AppendOutput($result, plist); + } + } +} + +%typemap(in, numinputs=0) semanage_ibendport_t **(semanage_ibendport_t *temp=NULL) { + $1 = &temp; +} + +%typemap(argout) semanage_ibendport_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(argout) semanage_ibendport_key_t ** { + $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0)); +} + +%typemap(in, numinputs=0) semanage_ibendport_key_t **(semanage_ibendport_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/src/semanageswig_ruby.i b/src/semanageswig_ruby.i new file mode 100644 index 0000000..e030e4a --- /dev/null +++ b/src/semanageswig_ruby.i @@ -0,0 +1,225 @@ +/* Author Dave Quigley + * based on semanageswig_python.i by Spencer Shimko + */ + +%header %{ + #include + #include + + #define STATUS_SUCCESS 0 + #define STATUS_ERR -1 +%} +/* a few helpful typemaps are available in this library */ +%include + +/* 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/src/seuser_internal.h b/src/seuser_internal.h new file mode 100644 index 0000000..bf9cab0 --- /dev/null +++ b/src/seuser_internal.h @@ -0,0 +1,43 @@ +#ifndef _SEMANAGE_SEUSER_INTERNAL_H_ +#define _SEMANAGE_SEUSER_INTERNAL_H_ + +#include +#include +#include +#include +#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/src/seuser_record.c b/src/seuser_record.c new file mode 100644 index 0000000..1ed4594 --- /dev/null +++ b/src/seuser_record.c @@ -0,0 +1,272 @@ +/* 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 +#include +#include "seuser_internal.h" +#include "debug.h" +#include +#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 */ + 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 = strdup(name); + if (!tmp_key->name) { + ERR(handle, "out of memory, could not create seuser key"); + free(tmp_key); + return STATUS_ERR; + } + + *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->name); + 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/src/seusers_file.c b/src/seusers_file.c new file mode 100644 index 0000000..910bedf --- /dev/null +++ b/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 +#include + +#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/src/seusers_local.c b/src/seusers_local.c new file mode 100644 index 0000000..a79e2d3 --- /dev/null +++ b/src/seusers_local.c @@ -0,0 +1,331 @@ +/* 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 +#include +#include +#include +#include "user_internal.h" +#include "seuser_internal.h" +#include "handle.h" +#include "database.h" +#include "debug.h" +#include "string.h" +#include + +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; imsg_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/src/seusers_policy.c b/src/seusers_policy.c new file mode 100644 index 0000000..89fb4d8 --- /dev/null +++ b/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 +#include +#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/src/user_base_record.c b/src/user_base_record.c new file mode 100644 index 0000000..7dfa8c6 --- /dev/null +++ b/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 + +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 +#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/src/user_extra_record.c b/src/user_extra_record.c new file mode 100644 index 0000000..efb9c5b --- /dev/null +++ b/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 + +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 +#include +#include +#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/src/user_internal.h b/src/user_internal.h new file mode 100644 index 0000000..ce1ac31 --- /dev/null +++ b/src/user_internal.h @@ -0,0 +1,177 @@ +#ifndef _SEMANAGE_USER_INTERNAL_H_ +#define _SEMANAGE_USER_INTERNAL_H_ + +#include +#include +#include +#include +#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/src/user_record.c b/src/user_record.c new file mode 100644 index 0000000..4523925 --- /dev/null +++ b/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 + +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 +#include +#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/src/users_base_file.c b/src/users_base_file.c new file mode 100644 index 0000000..0f0a8fd --- /dev/null +++ b/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 +#include +#include +#include +#include +#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/src/users_base_policydb.c b/src/users_base_policydb.c new file mode 100644 index 0000000..b42279c --- /dev/null +++ b/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 +#include +#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/src/users_extra_file.c b/src/users_extra_file.c new file mode 100644 index 0000000..8f2bebd --- /dev/null +++ b/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 +#include +#include + +#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/src/users_join.c b/src/users_join.c new file mode 100644 index 0000000..b598209 --- /dev/null +++ b/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 +#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/src/users_local.c b/src/users_local.c new file mode 100644 index 0000000..7aa43d4 --- /dev/null +++ b/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 +#include +#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 + * Paul Rosenfeld + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 off = 0; + + if (!str) + return NULL; + + /* skip one token and the spaces before and after it */ + off = strspn(str, seps); + off += strcspn(str + off, seps); + off += strspn(str + off, seps); + return strdup(str + off); +} + +char *semanage_split(const char *str, const char *delim) +{ + char *retval; + + if (!str) + return NULL; + if (!delim || !(*delim)) + return semanage_split_on_space(str); + + retval = strstr(str, delim); + if (retval == NULL) + return NULL; + + return strdup(retval + strlen(delim)); +} + +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(const 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; + } + } +} + +char *semanage_str_replace(const char *search, const char *replace, + const char *src, size_t lim) +{ + size_t count = 0, slen, rlen, newsize; + char *p, *pres, *result; + const char *psrc; + + slen = strlen(search); + rlen = strlen(replace); + + /* Do not support empty search strings */ + if (slen == 0) + return NULL; + + /* Count the occurences of search in src and compute the new size */ + for (p = strstr(src, search); p != NULL; p = strstr(p + slen, search)) { + count++; + if (lim && count >= lim) + break; + } + if (!count) + return strdup(src); + + /* Allocate the result string */ + newsize = strlen(src) + 1 + count * (rlen - slen); + result = malloc(newsize); + if (!result) + return NULL; + + /* Fill the result */ + psrc = src; + pres = result; + for (p = strstr(src, search); p != NULL; p = strstr(psrc, search)) { + /* Copy the part which has not been modified */ + if (p != psrc) { + size_t length = (size_t)(p - psrc); + memcpy(pres, psrc, length); + pres += length; + } + /* Copy the replacement part */ + if (rlen != 0) { + memcpy(pres, replace, rlen); + pres += rlen; + } + psrc = p + slen; + count--; + if (!count) + break; + } + /* Copy the last part, after doing a sanity check */ + assert(pres + strlen(psrc) + 1 == result + newsize); + strcpy(pres, psrc); + return result; +} + +/* 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/src/utilities.h b/src/utilities.h new file mode 100644 index 0000000..ba1ed02 --- /dev/null +++ b/src/utilities.h @@ -0,0 +1,147 @@ +/* Author: Mark Goldman + * + * 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 + +#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(const 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 value being searched for + * @param replacement value that replaces found search values + * @param string being searched and replaced on + * @param maximum number of value occurences (zero for unlimited) + * @return newly-allocated string with the replaced values + */ +char *semanage_str_replace(const char *search, const char *replace, + const char *src, size_t lim); + +/** + * @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/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..f07111d --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +libsemanage-tests diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..324766a --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,23 @@ +# Add your test source files here: +SOURCES = $(sort $(wildcard *.c)) + +########################################################################### + +EXECUTABLE = libsemanage-tests +CFLAGS += -g -O0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter +override CFLAGS += -I../src -I../include +override LDLIBS += -lcunit -lbz2 -laudit -lselinux -lsepol + +OBJECTS = $(SOURCES:.c=.o) + +all: $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) ../src/libsemanage.a + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean distclean: + rm -rf $(OBJECTS) $(EXECUTABLE) + +test: all + ./$(EXECUTABLE) + diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..424970c --- /dev/null +++ b/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 _test_init(void) + int _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/tests/libsemanage-tests.c b/tests/libsemanage-tests.c new file mode 100644 index 0000000..048751b --- /dev/null +++ b/tests/libsemanage-tests.c @@ -0,0 +1,111 @@ +/* Authors: Christopher Ashworth + * Caleb Case + * Chad Sellers + * + * 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 +#include +#include + +#include +#include +#include +#include + +#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 bool do_tests(int interactive, int verbose) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + /* 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(); + num_failures = CU_get_number_of_tests_failed(); + CU_cleanup_registry(); + return CU_get_error() == CUE_SUCCESS && num_failures == 0; + +} + +/* 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/tests/nc_sort_malformed b/tests/nc_sort_malformed new file mode 100644 index 0000000..85a2d46 --- /dev/null +++ b/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/tests/nc_sort_sorted b/tests/nc_sort_sorted new file mode 100644 index 0000000..5317a93 --- /dev/null +++ b/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/tests/nc_sort_unsorted b/tests/nc_sort_unsorted new file mode 100644 index 0000000..b399753 --- /dev/null +++ b/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/tests/test_semanage_store.c b/tests/test_semanage_store.c new file mode 100644 index 0000000..b324d50 --- /dev/null +++ b/tests/test_semanage_store.c @@ -0,0 +1,375 @@ +/* Authors: Christopher Ashworth + * Caleb Case + * Chris PeBenito + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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/tests/test_semanage_store.h b/tests/test_semanage_store.h new file mode 100644 index 0000000..3225497 --- /dev/null +++ b/tests/test_semanage_store.h @@ -0,0 +1,34 @@ +/* Authors: Christopher Ashworth + * Chris PeBenito + * + * 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 + +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/tests/test_utilities.c b/tests/test_utilities.c new file mode 100644 index 0000000..601508c --- /dev/null +++ b/tests/test_utilities.c @@ -0,0 +1,334 @@ +/* Authors: Mark Goldman + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +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_str_replace(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_str_replace", + test_semanage_str_replace)) { + 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) +{ + const char *str = "some string"; + const char *pre = "some"; + const 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); + CU_ASSERT_STRING_EQUAL(temp, "bar baz"); + free(str); + str = temp; + + temp = semanage_split_on_space(str); + CU_ASSERT_STRING_EQUAL(temp, "baz"); + free(str); + str = temp; + + temp = semanage_split_on_space(str); + CU_ASSERT_STRING_EQUAL(temp, ""); + free(str); + free(temp); +} + +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_STRING_EQUAL(temp, "foo2 foo:bar:"); + free(str); + str = temp; + + temp = semanage_split(str, ""); + CU_ASSERT_STRING_EQUAL(temp, "foo:bar:"); + free(str); + str = temp; + + temp = semanage_split(str, ":"); + CU_ASSERT_STRING_EQUAL(temp, "bar:"); + free(str); + str = temp; + + temp = semanage_split(str, ":"); + CU_ASSERT_STRING_EQUAL(temp, ""); + free(str); + free(temp); +} + +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) +{ + const 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"); + + free(str); +} + +void test_semanage_str_replace(void) +{ + const char *test_str = "Hello, I am %{USERNAME} and my id is %{USERID}"; + char *str1, *str2; + + str1 = semanage_str_replace("%{USERNAME}", "root", test_str, 0); + CU_ASSERT_STRING_EQUAL(str1, "Hello, I am root and my id is %{USERID}"); + + str2 = semanage_str_replace("%{USERID}", "0", str1, 1); + CU_ASSERT_STRING_EQUAL(str2, "Hello, I am root and my id is 0"); + free(str1); + free(str2); + + str1 = semanage_str_replace(":(", ";)", "Test :( :) ! :(:(:))(:(", 0); + CU_ASSERT_STRING_EQUAL(str1, "Test ;) :) ! ;);):))(;)"); + free(str1); + + str1 = semanage_str_replace(":(", ";)", "Test :( :) ! :(:(:))(:(", 3); + CU_ASSERT_STRING_EQUAL(str1, "Test ;) :) ! ;);):))(:("); + free(str1); + + str1 = semanage_str_replace("", "empty search string", "test", 0); + CU_ASSERT_EQUAL(str1, NULL); + + str1 = semanage_str_replace("a", "", "abracadabra", 0); + CU_ASSERT_STRING_EQUAL(str1, "brcdbr"); + free(str1); +} + +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, ""); + free(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"); + free(tok); +} + +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/tests/test_utilities.h b/tests/test_utilities.h new file mode 100644 index 0000000..4c95a68 --- /dev/null +++ b/tests/test_utilities.h @@ -0,0 +1,5 @@ +#include + +int semanage_utilities_test_init(void); +int semanage_utilities_test_cleanup(void); +int semanage_utilities_add_tests(CU_pSuite suite); diff --git a/tests/utilities.c b/tests/utilities.c new file mode 100644 index 0000000..7cc726c --- /dev/null +++ b/tests/utilities.c @@ -0,0 +1,32 @@ +/* Authors: Christopher Ashworth + * + * 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/tests/utilities.h b/tests/utilities.h new file mode 100644 index 0000000..781867d --- /dev/null +++ b/tests/utilities.h @@ -0,0 +1,23 @@ +/* Authors: Christopher Ashworth + * + * 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/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000..5b8fbb6 --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,19 @@ +# Installation directories. +PREFIX ?= /usr +LIBEXECDIR ?= $(PREFIX)/libexec +SELINUXEXECDIR ?= $(LIBEXECDIR)/selinux/ + +all: + +install: all + -mkdir -p $(DESTDIR)$(SELINUXEXECDIR) + install -m 755 semanage_migrate_store $(DESTDIR)$(SELINUXEXECDIR) + +clean: + +distclean: clean + +indent: + +relabel: + diff --git a/utils/semanage_migrate_store b/utils/semanage_migrate_store new file mode 100755 index 0000000..c6caf3b --- /dev/null +++ b/utils/semanage_migrate_store @@ -0,0 +1,296 @@ +#!/usr/bin/python3 -E + + +from __future__ import print_function +import os +import errno +import shutil +import sys +from optparse import OptionParser + + +try: + import selinux + import semanage +except ImportError: + 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 (IOError, OSError): + 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", + "pkeys.local", + "ibendports.local"] + + 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()